diff --git a/src/common/time/src/datetime.rs b/src/common/time/src/datetime.rs index 05d4884e95..5bdec5dc25 100644 --- a/src/common/time/src/datetime.rs +++ b/src/common/time/src/datetime.rs @@ -20,11 +20,12 @@ use serde::{Deserialize, Serialize}; use crate::error::{Error, InvalidDateStrSnafu, Result}; use crate::util::{format_utc_datetime, local_datetime_to_utc}; +use crate::Date; const DATETIME_FORMAT: &str = "%F %T"; const DATETIME_FORMAT_WITH_TZ: &str = "%F %T%z"; -/// [DateTime] represents the **seconds elapsed since "1970-01-01 00:00:00 UTC" (UNIX Epoch)**. +/// [DateTime] represents the **milliseconds elapsed since "1970-01-01 00:00:00 UTC" (UNIX Epoch)**. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, )] @@ -32,7 +33,7 @@ pub struct DateTime(i64); impl Display for DateTime { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if let Some(abs_time) = NaiveDateTime::from_timestamp_opt(self.0, 0) { + if let Some(abs_time) = NaiveDateTime::from_timestamp_millis(self.0) { write!( f, "{}", @@ -52,7 +53,7 @@ impl From for serde_json::Value { impl From for DateTime { fn from(value: NaiveDateTime) -> Self { - DateTime::from(value.timestamp()) + DateTime::from(value.timestamp_millis()) } } @@ -61,20 +62,20 @@ impl FromStr for DateTime { fn from_str(s: &str) -> Result { let s = s.trim(); - let timestamp = if let Ok(d) = NaiveDateTime::parse_from_str(s, DATETIME_FORMAT) { + let timestamp_millis = if let Ok(d) = NaiveDateTime::parse_from_str(s, DATETIME_FORMAT) { match local_datetime_to_utc(&d) { LocalResult::None => { return InvalidDateStrSnafu { raw: s }.fail(); } - LocalResult::Single(d) | LocalResult::Ambiguous(d, _) => d.timestamp(), + LocalResult::Single(d) | LocalResult::Ambiguous(d, _) => d.timestamp_millis(), } } else if let Ok(v) = chrono::DateTime::parse_from_str(s, DATETIME_FORMAT_WITH_TZ) { - v.timestamp() + v.timestamp_millis() } else { return InvalidDateStrSnafu { raw: s }.fail(); }; - Ok(Self(timestamp)) + Ok(Self(timestamp_millis)) } } @@ -84,6 +85,13 @@ impl From for DateTime { } } +impl From for DateTime { + fn from(value: Date) -> Self { + // It's safe, i32 * 86400000 won't be overflow + Self(value.to_secs() * 1000) + } +} + impl DateTime { pub fn new(val: i64) -> Self { Self(val) @@ -96,6 +104,10 @@ impl DateTime { pub fn to_chrono_datetime(&self) -> Option { NaiveDateTime::from_timestamp_opt(self.0, 0) } + + pub fn to_date(&self) -> Option { + self.to_chrono_datetime().map(|d| Date::from(d.date())) + } } #[cfg(test)] @@ -106,8 +118,8 @@ mod tests { pub fn test_new_date_time() { std::env::set_var("TZ", "Asia/Shanghai"); assert_eq!("1970-01-01 08:00:00+0800", DateTime::new(0).to_string()); - assert_eq!("1970-01-01 08:00:01+0800", DateTime::new(1).to_string()); - assert_eq!("1970-01-01 07:59:59+0800", DateTime::new(-1).to_string()); + assert_eq!("1970-01-01 08:00:01+0800", DateTime::new(1000).to_string()); + assert_eq!("1970-01-01 07:59:59+0800", DateTime::new(-1000).to_string()); } #[test] @@ -130,7 +142,7 @@ mod tests { fn test_parse_local_date_time() { std::env::set_var("TZ", "Asia/Shanghai"); assert_eq!( - -28800, + -28800000, DateTime::from_str("1970-01-01 00:00:00").unwrap().val() ); assert_eq!(0, DateTime::from_str("1970-01-01 08:00:00").unwrap().val()); @@ -141,6 +153,13 @@ mod tests { let ts = DateTime::from_str("1970-01-01 08:00:00+0000") .unwrap() .val(); - assert_eq!(28800, ts); + assert_eq!(28800000, ts); + } + + #[test] + fn test_from_max_date() { + let date = Date::new(i32::MAX); + let datetime = DateTime::from(date); + assert_eq!(datetime.val(), 185542587100800000); } } diff --git a/src/datatypes/src/types/datetime_type.rs b/src/datatypes/src/types/datetime_type.rs index cd0e5a3cd1..17326ef9ae 100644 --- a/src/datatypes/src/types/datetime_type.rs +++ b/src/datatypes/src/types/datetime_type.rs @@ -122,7 +122,7 @@ mod tests { ); // cast from Timestamp - let val = Value::Timestamp(Timestamp::from_str("2020-09-08 21:42:29.042+0800").unwrap()); + let val = Value::Timestamp(Timestamp::from_str("2020-09-08 21:42:29+0800").unwrap()); let dt = ConcreteDataType::datetime_datatype().try_cast(val).unwrap(); assert_eq!( dt, diff --git a/src/datatypes/src/vectors/datetime.rs b/src/datatypes/src/vectors/datetime.rs index 55cd901561..4ae654cc3e 100644 --- a/src/datatypes/src/vectors/datetime.rs +++ b/src/datatypes/src/vectors/datetime.rs @@ -38,7 +38,7 @@ mod tests { #[test] fn test_datetime_vector() { std::env::set_var("TZ", "Asia/Shanghai"); - let v = DateTimeVector::new(PrimitiveArray::from(vec![1, 2, 3])); + let v = DateTimeVector::new(PrimitiveArray::from(vec![1000, 2000, 3000])); assert_eq!(ConcreteDataType::datetime_datatype(), v.data_type()); assert_eq!(3, v.len()); assert_eq!("DateTimeVector", v.vector_type_name()); @@ -47,19 +47,19 @@ mod tests { v.to_arrow_array().data_type() ); - assert_eq!(Some(DateTime::new(1)), v.get_data(0)); - assert_eq!(Value::DateTime(DateTime::new(1)), v.get(0)); - assert_eq!(ValueRef::DateTime(DateTime::new(1)), v.get_ref(0)); + assert_eq!(Some(DateTime::new(1000)), v.get_data(0)); + assert_eq!(Value::DateTime(DateTime::new(1000)), v.get(0)); + assert_eq!(ValueRef::DateTime(DateTime::new(1000)), v.get_ref(0)); let mut iter = v.iter_data(); - assert_eq!(Some(DateTime::new(1)), iter.next().unwrap()); - assert_eq!(Some(DateTime::new(2)), iter.next().unwrap()); - assert_eq!(Some(DateTime::new(3)), iter.next().unwrap()); + assert_eq!(Some(DateTime::new(1000)), iter.next().unwrap()); + assert_eq!(Some(DateTime::new(2000)), iter.next().unwrap()); + assert_eq!(Some(DateTime::new(3000)), iter.next().unwrap()); assert!(!v.is_null(0)); assert_eq!(24, v.memory_size()); if let Value::DateTime(d) = v.get(0) { - assert_eq!(1, d.val()); + assert_eq!(1000, d.val()); } else { unreachable!() }