Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into feat-metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
everpcpc committed Nov 5, 2024
2 parents 6232187 + 31b7ceb commit ea28c67
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
56 changes: 56 additions & 0 deletions src/query/functions/src/scalars/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ pub fn register(registry: &mut FunctionRegistry) {

// [date | timestamp] +/- number
register_timestamp_add_sub(registry);

// convert_timezone( target_timezone, 'timestamp')
register_convert_timezone(registry);
}

/// Check if timestamp is within range, and return the timestamp in micros.
Expand All @@ -134,6 +137,59 @@ fn int64_domain_to_timestamp_domain<T: AsPrimitive<i64>>(
})
}

fn register_convert_timezone(registry: &mut FunctionRegistry) {
// 2 arguments function [target_timezone, src_timestamp]
registry.register_passthrough_nullable_2_arg::<StringType, TimestampType, TimestampType, _, _>(
"convert_timezone",
|_, _, _| FunctionDomain::MayThrow,
vectorize_with_builder_2_arg::<StringType, TimestampType, TimestampType>(
|target_tz, src_timestamp, output, ctx| {
if let Some(validity) = &ctx.validity {
if !validity.get_bit(output.len()) {
output.push(0);
return;
}
}
// Convert source timestamp from source timezone to target timezone
let p_src_timestamp = src_timestamp.to_timestamp(ctx.func_ctx.tz.tz);
let src_dst_from_utc = p_src_timestamp.offset().fix().local_minus_utc();
let t_tz: Tz = match target_tz.parse() {
Ok(tz) => tz,
Err(e) => {
ctx.set_error(
output.len(),
format!("cannot parse target `timezone`. {}", e),
);
output.push(0);
return;
}
};

let result_timestamp = p_src_timestamp.with_timezone(&t_tz).timestamp_micros();
let target_dst_from_utc = p_src_timestamp
.with_timezone(&t_tz)
.offset()
.fix()
.local_minus_utc();
let offset_as_micros_sec = (target_dst_from_utc - src_dst_from_utc) as i64;
match offset_as_micros_sec.checked_mul(MICROS_PER_SEC) {
Some(offset) => match result_timestamp.checked_add(offset) {
Some(res) => output.push(res),
None => {
ctx.set_error(output.len(), "calc final time error".to_string());
output.push(0);
}
},
None => {
ctx.set_error(output.len(), "calc time offset error".to_string());
output.push(0);
}
}
},
),
);
}

fn register_string_to_timestamp(registry: &mut FunctionRegistry) {
registry.register_aliases("to_date", &["str_to_date", "date"]);
registry.register_aliases("to_year", &["str_to_year", "year"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,8 @@ Functions overloads:
26 contains(Array(Boolean), Boolean) :: Boolean
27 contains(Array(Boolean) NULL, Boolean NULL) :: Boolean NULL
28 contains(Array(T0) NULL, T0) :: Boolean
0 convert_timezone(String, Timestamp) :: Timestamp
1 convert_timezone(String NULL, Timestamp NULL) :: Timestamp NULL
0 cos(Float64) :: Float64
1 cos(Float64 NULL) :: Float64 NULL
0 cosine_distance(Array(Float32), Array(Float32)) :: Float32
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,6 @@ select to_datetime('1', '%s')
statement error 1006
select to_timestamp('200,2000', '%s,%Y');


statement ok
set timezone='UTC';

Expand Down Expand Up @@ -769,3 +768,59 @@ query T
SELECT substr(DATE_ADD(month, 1, now())::String, 1,4)=substr(now()::String, 1,4);
----
1


statement ok
set timezone='Asia/Shanghai';

query T
SELECT convert_timezone('America/Los_Angeles', '2024-11-01 11:36:10')
----
2024-10-31 20:36:10.000000

statement ok
set timezone='UTC';

statement ok
create or replace table t(a string null, c timestamp null);

statement ok
insert into t values('America/Los_Angeles','1970-01-01 00:00:00'), ('America/Los_Angeles','2024-10-31 22:21:15'), (null, '1970-01-01 00:00:00'), ('Asia/Shanghai', '1970-01-01 00:00:00'), ('Asia/Shanghai', '2024-10-31 22:21:15'),('Asia/Shanghai', null), (null, null);

# UTC to America/Los_Angeles, 20240-03-10 ~ 2024-11-03 is UTC-7(dst), other is UTC-8
query T
select a, c, CONVERT_TIMEZONE(a, c) from t order by a,c;
----
America/Los_Angeles 1970-01-01 00:00:00.000000 1969-12-31 16:00:00.000000
America/Los_Angeles 2024-10-31 22:21:15.000000 2024-10-31 15:21:15.000000
Asia/Shanghai 1970-01-01 00:00:00.000000 1970-01-01 08:00:00.000000
Asia/Shanghai 2024-10-31 22:21:15.000000 2024-11-01 06:21:15.000000
Asia/Shanghai NULL NULL
NULL 1970-01-01 00:00:00.000000 NULL
NULL NULL NULL

statement ok
set timezone='Asia/Shanghai';


statement error 1006
select convert_timezone('Asia/Shanghai', '1947-04-15 00:00:00');

statement ok
set enable_dst_hour_fix=1;

# 1947-04-15 00:00:00 is not exists in Asia/Shanghai. Such timings cannot be guaranteed to meet completely
# consider use date_add/sub calc the offset.
query T
select convert_timezone('UTC', '1947-04-15 00:00:00');
----
1947-04-14 15:00:00.000000

statement ok
unset enable_dst_hour_fix;

statement ok
drop table if exists t;

statement ok
unset timezone;

0 comments on commit ea28c67

Please sign in to comment.