Skip to content

Commit

Permalink
Store dates as PrimitiveDateTime with implicit time zone UTC
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde committed Mar 10, 2022
1 parent 431a901 commit 304013f
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/fastfield/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ fn value_to_u64(value: &Value) -> u64 {
Value::U64(ref val) => *val,
Value::I64(ref val) => common::i64_to_u64(*val),
Value::F64(ref val) => common::f64_to_u64(*val),
Value::Date(ref datetime) => common::i64_to_u64(datetime.unix_timestamp()),
Value::Date(ref datetime) => common::i64_to_u64(datetime.assume_utc().unix_timestamp()),
_ => panic!("Expected a u64/i64/f64 field, got {:?} ", value),
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/fastfield/multivalued/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ mod tests {
.expect("cannot find value")
.as_date()
.unwrap()
.assume_utc()
.unix_timestamp(),
first_time_stamp.unix_timestamp()
);
Expand Down Expand Up @@ -138,6 +139,7 @@ mod tests {
.expect("cannot find value")
.as_date()
.unwrap()
.assume_utc()
.unix_timestamp(),
two_secs_ahead.unix_timestamp()
);
Expand Down Expand Up @@ -180,6 +182,7 @@ mod tests {
.expect("cannot find value")
.as_date()
.expect("value not of Date type")
.assume_utc()
.unix_timestamp(),
(first_time_stamp + Duration::seconds(offset_sec)).unix_timestamp()
);
Expand Down
2 changes: 1 addition & 1 deletion src/indexer/segment_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ impl SegmentWriter {
FieldType::Date(_) => {
for value in values {
let date_val = value.as_date().ok_or_else(make_schema_error)?;
term_buffer.set_i64(date_val.unix_timestamp());
term_buffer.set_i64(date_val.assume_utc().unix_timestamp());
postings_writer.subscribe(doc_id, 0u32, term_buffer, ctx);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/query/more_like_this/more_like_this.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ impl MoreLikeThis {
let val = value
.as_date()
.ok_or_else(|| TantivyError::InvalidArgument("invalid value".to_string()))?
.assume_utc()
.unix_timestamp();
if !self.is_noise_word(val.to_string()) {
let term = Term::from_field_i64(field, val);
Expand Down
9 changes: 4 additions & 5 deletions src/schema/field_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::schema::{
Value,
};
use crate::time::format_description::well_known::Rfc3339;
use crate::time::{OffsetDateTime, UtcOffset};
use crate::time::OffsetDateTime;
use crate::tokenizer::PreTokenizedString;

/// Possible error that may occur while parsing a field value
Expand Down Expand Up @@ -253,7 +253,7 @@ impl FieldType {
expected: "rfc3339 format",
json: JsonValue::String(field_text),
})?;
Ok(Value::Date(dt_with_fixed_tz.to_offset(UtcOffset::UTC)))
Ok(dt_with_fixed_tz.into())
}
FieldType::Str(_) => Ok(Value::Str(field_text)),
FieldType::U64(_) | FieldType::I64(_) | FieldType::F64(_) => {
Expand Down Expand Up @@ -362,9 +362,8 @@ mod tests {
let date = doc.get_first(date_field).unwrap();
assert_eq!(
format!("{:?}", date),
"Date(OffsetDateTime { utc_datetime: PrimitiveDateTime { date: Date { year: 2019, \
ordinal: 285 }, time: Time { hour: 5, minute: 20, second: 50, nanosecond: 520000000 \
} }, offset: UtcOffset { hours: 0, minutes: 0, seconds: 0 } })"
"Date(PrimitiveDateTime { date: Date { year: 2019, ordinal: 285 }, time: Time { hour: \
5, minute: 20, second: 50, nanosecond: 520000000 } })"
);
}

Expand Down
47 changes: 30 additions & 17 deletions src/schema/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Map;

use crate::schema::Facet;
use crate::time::OffsetDateTime;
use crate::time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
use crate::tokenizer::PreTokenizedString;

/// Value represents the value of a any field.
Expand All @@ -23,7 +23,10 @@ pub enum Value {
/// 64-bits Float `f64`
F64(f64),
/// Signed 64-bits Date time stamp `date`
Date(OffsetDateTime),
///
/// Stored as seconds since the UNIX epoch origin. Internally
/// the time zone is assumed to be UTC.
Date(PrimitiveDateTime),
/// Facet
Facet(Facet),
/// Arbitrarily sized byte array
Expand All @@ -43,7 +46,9 @@ impl Serialize for Value {
Value::U64(u) => serializer.serialize_u64(u),
Value::I64(u) => serializer.serialize_i64(u),
Value::F64(u) => serializer.serialize_f64(u),
Value::Date(ref date) => time::serde::rfc3339::serialize(date, serializer),
Value::Date(ref date) => {
time::serde::rfc3339::serialize(&date.assume_utc(), serializer)
}
Value::Facet(ref facet) => facet.serialize(serializer),
Value::Bytes(ref bytes) => serializer.serialize_bytes(bytes),
Value::JsonObject(ref obj) => obj.serialize(serializer),
Expand Down Expand Up @@ -154,7 +159,7 @@ impl Value {
/// Returns the Date-value, provided the value is of the `Date` type.
///
/// Returns None if the value is not of type `Date`.
pub fn as_date(&self) -> Option<&OffsetDateTime> {
pub fn as_date(&self) -> Option<&PrimitiveDateTime> {
if let Value::Date(date) = self {
Some(date)
} else {
Expand Down Expand Up @@ -209,9 +214,16 @@ impl From<f64> for Value {
}
}

impl From<PrimitiveDateTime> for Value {
fn from(date_time: PrimitiveDateTime) -> Value {
Value::Date(date_time)
}
}

impl From<OffsetDateTime> for Value {
fn from(date_time: OffsetDateTime) -> Value {
Value::Date(date_time)
let utc = date_time.to_offset(UtcOffset::UTC);
PrimitiveDateTime::new(utc.date(), utc.time()).into()
}
}

Expand Down Expand Up @@ -319,7 +331,7 @@ mod binary_serialize {
}
Value::Date(ref val) => {
DATE_CODE.serialize(writer)?;
val.unix_timestamp().serialize(writer)
val.assume_utc().unix_timestamp().serialize(writer)
}
Value::Facet(ref facet) => {
HIERARCHICAL_FACET_CODE.serialize(writer)?;
Expand Down Expand Up @@ -358,14 +370,13 @@ mod binary_serialize {
}
DATE_CODE => {
let timestamp = i64::deserialize(reader)?;
Ok(Value::Date(
OffsetDateTime::from_unix_timestamp(timestamp).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Invalid UNIX timestamp: {}", err),
)
})?,
))
let dt = OffsetDateTime::from_unix_timestamp(timestamp).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Invalid UNIX timestamp: {}", err),
)
})?;
Ok(dt.into())
}
HIERARCHICAL_FACET_CODE => Ok(Value::Facet(Facet::deserialize(reader)?)),
BYTES_CODE => Ok(Value::Bytes(Vec::<u8>::deserialize(reader)?)),
Expand Down Expand Up @@ -415,12 +426,14 @@ mod tests {
#[test]
fn test_serialize_date() {
let value =
Value::Date(OffsetDateTime::parse("1996-12-20T00:39:57+00:00", &Rfc3339).unwrap());
Value::from(OffsetDateTime::parse("1996-12-20T00:39:57+00:00", &Rfc3339).unwrap());
let serialized_value_json = serde_json::to_string_pretty(&value).unwrap();
assert_eq!(serialized_value_json, r#""1996-12-20T00:39:57Z""#);
let value =
Value::Date(OffsetDateTime::parse("1996-12-20T00:39:57-01:00", &Rfc3339).unwrap());
Value::from(OffsetDateTime::parse("1996-12-20T00:39:57-01:00", &Rfc3339).unwrap());
let serialized_value_json = serde_json::to_string_pretty(&value).unwrap();
assert_eq!(serialized_value_json, r#""1996-12-20T00:39:57-01:00""#);
// The time zone information gets lost by conversion into `Value::Date` and
// implicitly becomes UTC.
assert_eq!(serialized_value_json, r#""1996-12-20T01:39:57Z""#);
}
}

0 comments on commit 304013f

Please sign in to comment.