diff --git a/e2e_test/batch/functions/timezone.slt.part b/e2e_test/batch/functions/timezone.slt.part new file mode 100644 index 0000000000000..344e00e735dc0 --- /dev/null +++ b/e2e_test/batch/functions/timezone.slt.part @@ -0,0 +1,112 @@ +statement ok +SET TimeZone to 'UTC'; + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 02:00:00'::timestamp); +---- +2011-03-26 23:00:00+00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 02:59:59'::timestamp); +---- +2011-03-26 23:59:59+00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 03:00:00'::timestamp); +---- +2011-03-26 23:00:00+00:00 + +query T +SELECT timezone('Europe/Moscow', '2014-10-26 00:59:59'::timestamp); +---- +2014-10-25 20:59:59+00:00 + +query T +SELECT timezone('Europe/Moscow', '2014-10-26 01:00:00'::timestamp); +---- +2014-10-25 22:00:00+00:00 + +query T +SELECT timezone('Europe/Moscow', '2014-10-26 01:00:01'::timestamp); +---- +2014-10-25 22:00:01+00:00 + +query T +SELECT timezone('Asia/Shanghai', '2024-11-20 20:00:00 UTC'::timestamptz); +---- +2024-11-21 04:00:00 + +query T +SELECT timezone('Asia/Shanghai', '2023-02-28 20:00:00 UTC'::timestamptz); +---- +2023-03-01 04:00:00 + +query T +SELECT timezone('Asia/Shanghai', '2024-02-28 20:00:00 UTC'::timestamptz); +---- +2024-02-29 04:00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-26 22:00:00 UTC'::timestamptz); +---- +2011-03-27 01:00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-26 23:00:00 UTC'::timestamptz); +---- +2011-03-27 03:00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-26 23:00:01 UTC'::timestamptz); +---- +2011-03-27 03:00:01 + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 01:00:00 UTC'::timestamptz); +---- +2011-03-27 05:00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 02:00:00 UTC'::timestamptz); +---- +2011-03-27 06:00:00 + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 02:59:59 UTC'::timestamptz); +---- +2011-03-27 06:59:59 + +query T +SELECT timezone('Europe/Moscow', '2011-03-27 03:00:00 UTC'::timestamptz); +---- +2011-03-27 07:00:00 + +query T +SELECT timezone('Europe/Moscow', '2014-10-25 21:59:59 UTC'::timestamptz); +---- +2014-10-26 01:59:59 + +query T +SELECT timezone('Europe/Moscow', '2014-10-25 22:00:00 UTC'::timestamptz); +---- +2014-10-26 01:00:00 + +query T +SELECT timezone('Europe/Moscow', '2014-10-25 22:59:59 UTC'::timestamptz); +---- +2014-10-26 01:59:59 + +query T +SELECT timezone('Europe/Moscow', '2014-10-25 23:00:00 UTC'::timestamptz); +---- +2014-10-26 02:00:00 + +query T +SELECT timezone('Europe/Moscow', '2014-10-25 23:00:01 UTC'::timestamptz); +---- +2014-10-26 02:00:01 + +query T +SELECT timezone('Europe/Moscow', '2014-10-26 02:00:01 UTC'::timestamptz); +---- +2014-10-26 05:00:01 diff --git a/src/expr/impl/src/scalar/timestamptz.rs b/src/expr/impl/src/scalar/timestamptz.rs index 7dcc718d728ef..06f9f2a7ffba4 100644 --- a/src/expr/impl/src/scalar/timestamptz.rs +++ b/src/expr/impl/src/scalar/timestamptz.rs @@ -41,6 +41,14 @@ pub fn f64_sec_to_timestamptz(elem: F64) -> Result { Ok(Timestamptz::from_micros(micros)) } +#[function("at_time_zone(timestamptz, varchar) -> timestamp")] +pub fn timestamptz_at_time_zone(input: Timestamptz, time_zone: &str) -> Result { + let time_zone = Timestamptz::lookup_time_zone(time_zone).map_err(time_zone_err)?; + let instant_local = input.to_datetime_in_zone(time_zone); + let naive = instant_local.naive_local(); + Ok(Timestamp(naive)) +} + #[function("at_time_zone(timestamp, varchar) -> timestamptz")] pub fn timestamp_at_time_zone(input: Timestamp, time_zone: &str) -> Result { let time_zone = Timestamptz::lookup_time_zone(time_zone).map_err(time_zone_err)?; @@ -96,14 +104,6 @@ pub fn str_to_timestamptz(elem: &str, time_zone: &str) -> Result { }) } -#[function("at_time_zone(timestamptz, varchar) -> timestamp")] -pub fn timestamptz_at_time_zone(input: Timestamptz, time_zone: &str) -> Result { - let time_zone = Timestamptz::lookup_time_zone(time_zone).map_err(time_zone_err)?; - let instant_local = input.to_datetime_in_zone(time_zone); - let naive = instant_local.naive_local(); - Ok(Timestamp(naive)) -} - /// This operation is zone agnostic. #[function("subtract(timestamptz, timestamptz) -> interval")] pub fn timestamptz_timestamptz_sub(l: Timestamptz, r: Timestamptz) -> Result { diff --git a/src/frontend/src/binder/expr/function/builtin_scalar.rs b/src/frontend/src/binder/expr/function/builtin_scalar.rs index 66c28b0ba24d6..7570f72c5d095 100644 --- a/src/frontend/src/binder/expr/function/builtin_scalar.rs +++ b/src/frontend/src/binder/expr/function/builtin_scalar.rs @@ -210,7 +210,7 @@ impl Binder { ("scale", raw_call(ExprType::Scale)), ("min_scale", raw_call(ExprType::MinScale)), ("trim_scale", raw_call(ExprType::TrimScale)), - + // date and time ( "to_timestamp", dispatch_by_len(vec![ @@ -223,8 +223,16 @@ impl Binder { ("make_date", raw_call(ExprType::MakeDate)), ("make_time", raw_call(ExprType::MakeTime)), ("make_timestamp", raw_call(ExprType::MakeTimestamp)), - ("to_date", raw_call(ExprType::CharToDate)), ("make_timestamptz", raw_call(ExprType::MakeTimestamptz)), + ("timezone", rewrite(ExprType::AtTimeZone, |mut inputs|{ + if inputs.len() == 2 { + inputs.swap(0, 1); + Ok(inputs) + } else { + Err(ErrorCode::ExprError("unexpected arguments number".into()).into()) + } + })), + ("to_date", raw_call(ExprType::CharToDate)), // string ("substr", raw_call(ExprType::Substr)), ("length", raw_call(ExprType::Length)), diff --git a/src/tests/regress/data/schedule b/src/tests/regress/data/schedule index d1cfd9ab86253..54cf97a5ed4d6 100644 --- a/src/tests/regress/data/schedule +++ b/src/tests/regress/data/schedule @@ -12,4 +12,4 @@ test: strings date time timestamp interval test: case arrays delete test: jsonb jsonb_jsonpath test: regex -test: contrib-pgcrypto-rijndael +test: contrib-pgcrypto-rijndael \ No newline at end of file