From 0ce2b50676cacff608abe3af8a36195041d8c7fb Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Tue, 12 Dec 2023 20:41:05 +0800 Subject: [PATCH] feat!: do not get TZ info from server local env (#2905) * feat: do not get TZ info from server local env Signed-off-by: Ruihang Xia * add sqlness case Signed-off-by: Ruihang Xia * add empty line Signed-off-by: Ruihang Xia * fix typo Signed-off-by: Ruihang Xia --------- Signed-off-by: Ruihang Xia --- src/common/time/src/timestamp.rs | 96 +++---------------- src/datatypes/src/types/date_type.rs | 8 +- src/datatypes/src/types/timestamp_type.rs | 4 +- .../common/timestamp/timestamp.result | 28 ++++++ .../standalone/common/timestamp/timestamp.sql | 10 ++ 5 files changed, 63 insertions(+), 83 deletions(-) diff --git a/src/common/time/src/timestamp.rs b/src/common/time/src/timestamp.rs index e8cf29a68737..0e40082378ce 100644 --- a/src/common/time/src/timestamp.rs +++ b/src/common/time/src/timestamp.rs @@ -21,15 +21,14 @@ use std::time::Duration; use arrow::datatypes::TimeUnit as ArrowTimeUnit; use chrono::{ - DateTime, Days, LocalResult, Months, NaiveDate, NaiveDateTime, NaiveTime, - TimeZone as ChronoTimeZone, Utc, + DateTime, Days, Months, NaiveDate, NaiveDateTime, NaiveTime, TimeZone as ChronoTimeZone, Utc, }; use serde::{Deserialize, Serialize}; use snafu::{OptionExt, ResultExt}; use crate::error::{ArithmeticOverflowSnafu, Error, ParseTimestampSnafu, TimestampOverflowSnafu}; use crate::timezone::TimeZone; -use crate::util::{div_ceil, format_utc_datetime, local_datetime_to_utc}; +use crate::util::{div_ceil, format_utc_datetime}; use crate::{error, Interval}; /// Timestamp represents the value of units(seconds/milliseconds/microseconds/nanoseconds) elapsed @@ -364,11 +363,11 @@ impl FromStr for Timestamp { /// Supported format: /// - `2022-09-20T14:16:43.012345Z` (Zulu timezone) /// - `2022-09-20T14:16:43.012345+08:00` (Explicit offset) - /// - `2022-09-20T14:16:43.012345` (local timezone, with T) - /// - `2022-09-20T14:16:43` (local timezone, no fractional seconds, with T) + /// - `2022-09-20T14:16:43.012345` (Zulu timezone, with T) + /// - `2022-09-20T14:16:43` (Zulu timezone, no fractional seconds, with T) /// - `2022-09-20 14:16:43.012345Z` (Zulu timezone, without T) - /// - `2022-09-20 14:16:43` (local timezone, without T) - /// - `2022-09-20 14:16:43.012345` (local timezone, without T) + /// - `2022-09-20 14:16:43` (Zulu timezone, without T) + /// - `2022-09-20 14:16:43.012345` (Zulu timezone, without T) #[allow(deprecated)] fn from_str(s: &str) -> Result { // RFC3339 timestamp (with a T) @@ -407,18 +406,13 @@ impl FromStr for Timestamp { } /// Converts the naive datetime (which has no specific timezone) to a -/// nanosecond epoch timestamp relative to UTC. -/// This code is copied from [arrow-datafusion](https://github.com/apache/arrow-datafusion/blob/arrow2/datafusion-physical-expr/src/arrow_temporal_util.rs#L137). +/// nanosecond epoch timestamp in UTC. fn naive_datetime_to_timestamp( s: &str, datetime: NaiveDateTime, ) -> crate::error::Result { - match local_datetime_to_utc(&datetime) { - LocalResult::None => ParseTimestampSnafu { raw: s }.fail(), - LocalResult::Single(utc) | LocalResult::Ambiguous(utc, _) => { - Timestamp::from_chrono_datetime(utc).context(ParseTimestampSnafu { raw: s }) - } - } + Timestamp::from_chrono_datetime(Utc.from_utc_datetime(&datetime).naive_utc()) + .context(ParseTimestampSnafu { raw: s }) } impl From for Timestamp { @@ -562,7 +556,6 @@ impl Hash for Timestamp { mod tests { use std::collections::hash_map::DefaultHasher; - use chrono::{Local, Offset}; use rand::Rng; use serde_json::Value; @@ -783,71 +776,11 @@ mod tests { check_from_str("2020-09-08 13:42:29Z", "2020-09-08 13:42:29"); check_from_str("2020-09-08T13:42:29+08:00", "2020-09-08 05:42:29"); - check_from_str( - "2020-09-08 13:42:29", - &NaiveDateTime::from_timestamp_opt( - 1599572549 - - Local - .timestamp_opt(0, 0) - .unwrap() - .offset() - .fix() - .local_minus_utc() as i64, - 0, - ) - .unwrap() - .to_string(), - ); - - check_from_str( - "2020-09-08T13:42:29", - &NaiveDateTime::from_timestamp_opt( - 1599572549 - - Local - .timestamp_opt(0, 0) - .unwrap() - .offset() - .fix() - .local_minus_utc() as i64, - 0, - ) - .unwrap() - .to_string(), - ); + check_from_str("2020-09-08 13:42:29", "2020-09-08 13:42:29"); - check_from_str( - "2020-09-08 13:42:29.042", - &NaiveDateTime::from_timestamp_opt( - 1599572549 - - Local - .timestamp_opt(0, 0) - .unwrap() - .offset() - .fix() - .local_minus_utc() as i64, - 42000000, - ) - .unwrap() - .to_string(), - ); check_from_str("2020-09-08 13:42:29.042Z", "2020-09-08 13:42:29.042"); check_from_str("2020-09-08 13:42:29.042+08:00", "2020-09-08 05:42:29.042"); - check_from_str( - "2020-09-08T13:42:29.042", - &NaiveDateTime::from_timestamp_opt( - 1599572549 - - Local - .timestamp_opt(0, 0) - .unwrap() - .offset() - .fix() - .local_minus_utc() as i64, - 42000000, - ) - .unwrap() - .to_string(), - ); - check_from_str("2020-09-08T13:42:29+08:00", "2020-09-08 05:42:29"); + check_from_str( "2020-09-08T13:42:29.0042+08:00", "2020-09-08 05:42:29.004200", @@ -1119,21 +1052,22 @@ mod tests { assert_eq!(TimeUnit::Second, res.unit); } + // $TZ doesn't take effort. #[test] fn test_parse_in_time_zone() { std::env::set_var("TZ", "Asia/Shanghai"); assert_eq!( - Timestamp::new(0, TimeUnit::Nanosecond), + Timestamp::new(28800, TimeUnit::Second), Timestamp::from_str("1970-01-01 08:00:00.000").unwrap() ); assert_eq!( - Timestamp::new(0, TimeUnit::Second), + Timestamp::new(28800, TimeUnit::Second), Timestamp::from_str("1970-01-01 08:00:00").unwrap() ); assert_eq!( - Timestamp::new(0, TimeUnit::Second), + Timestamp::new(28800, TimeUnit::Second), Timestamp::from_str(" 1970-01-01 08:00:00 ").unwrap() ); } diff --git a/src/datatypes/src/types/date_type.rs b/src/datatypes/src/types/date_type.rs index fe32f00b26c8..89a8889cf8f6 100644 --- a/src/datatypes/src/types/date_type.rs +++ b/src/datatypes/src/types/date_type.rs @@ -105,6 +105,7 @@ mod tests { use super::*; + // $TZ doesn't take effort #[test] fn test_date_cast() { std::env::set_var("TZ", "Asia/Shanghai"); @@ -113,9 +114,14 @@ mod tests { let date = ConcreteDataType::date_datatype().try_cast(ts).unwrap(); assert_eq!(date, Value::Date(Date::from_str("2000-01-01").unwrap())); - // this case bind with local timezone. + // this case bind with Zulu timezone. let ts = Value::Timestamp(Timestamp::from_str("2000-01-02 07:59:59").unwrap()); let date = ConcreteDataType::date_datatype().try_cast(ts).unwrap(); + assert_eq!(date, Value::Date(Date::from_str("2000-01-02").unwrap())); + + // while this case is offsetted to Asia/Shanghai. + let ts = Value::Timestamp(Timestamp::from_str("2000-01-02 07:59:59+08:00").unwrap()); + let date = ConcreteDataType::date_datatype().try_cast(ts).unwrap(); assert_eq!(date, Value::Date(Date::from_str("2000-01-01").unwrap())); // Int32 -> date diff --git a/src/datatypes/src/types/timestamp_type.rs b/src/datatypes/src/types/timestamp_type.rs index 389e6fcc4624..ffd63228b098 100644 --- a/src/datatypes/src/types/timestamp_type.rs +++ b/src/datatypes/src/types/timestamp_type.rs @@ -227,6 +227,7 @@ mod tests { ); } + // $TZ doesn't take effort #[test] fn test_timestamp_cast() { std::env::set_var("TZ", "Asia/Shanghai"); @@ -235,7 +236,8 @@ mod tests { let ts = ConcreteDataType::timestamp_second_datatype() .try_cast(s) .unwrap(); - assert_eq!(ts, Value::Timestamp(Timestamp::new_second(1609434123))); + // 1609462923 is 2021-01-01T01:02:03Z + assert_eq!(ts, Value::Timestamp(Timestamp::new_second(1609462923))); // String cast failed let s = Value::String("12345".to_string().into()); let ts = ConcreteDataType::timestamp_second_datatype().try_cast(s); diff --git a/tests/cases/standalone/common/timestamp/timestamp.result b/tests/cases/standalone/common/timestamp/timestamp.result index 331f1c8dc865..3039fb65a4dc 100644 --- a/tests/cases/standalone/common/timestamp/timestamp.result +++ b/tests/cases/standalone/common/timestamp/timestamp.result @@ -82,3 +82,31 @@ DROP TABLE timestamp_with_precision; Affected Rows: 0 +CREATE TABLE plain_timestamp (ts TIMESTAMP TIME INDEX); + +Affected Rows: 0 + +INSERT INTO plain_timestamp VALUES (1); + +Affected Rows: 1 + +SELECT * FROM plain_timestamp; + ++-------------------------+ +| ts | ++-------------------------+ +| 1970-01-01T00:00:00.001 | ++-------------------------+ + +SELECT * FROM plain_timestamp where ts = '1970-01-01 00:00:00.001000'; + ++-------------------------+ +| ts | ++-------------------------+ +| 1970-01-01T00:00:00.001 | ++-------------------------+ + +DROP TABLE plain_timestamp; + +Affected Rows: 0 + diff --git a/tests/cases/standalone/common/timestamp/timestamp.sql b/tests/cases/standalone/common/timestamp/timestamp.sql index 19ac7e64e553..2e2fb9ec4493 100644 --- a/tests/cases/standalone/common/timestamp/timestamp.sql +++ b/tests/cases/standalone/common/timestamp/timestamp.sql @@ -29,3 +29,13 @@ INSERT INTO timestamp_with_precision(ts,cnt) VALUES ('2262-04-11 23:47:16.854775 SELECT * FROM timestamp_with_precision ORDER BY ts ASC; DROP TABLE timestamp_with_precision; + +CREATE TABLE plain_timestamp (ts TIMESTAMP TIME INDEX); + +INSERT INTO plain_timestamp VALUES (1); + +SELECT * FROM plain_timestamp; + +SELECT * FROM plain_timestamp where ts = '1970-01-01 00:00:00.001000'; + +DROP TABLE plain_timestamp;