Skip to content

Commit

Permalink
fix the case in Australia/Lord_Howe where the shift is 30 min
Browse files Browse the repository at this point in the history
Signed-off-by: Runji Wang <[email protected]>
  • Loading branch information
wangrunji0408 committed Mar 14, 2024
1 parent 8c1db7a commit babd349
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 19 deletions.
1 change: 0 additions & 1 deletion e2e_test/batch/functions/issue_12072.slt.part
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ select date_trunc('day', v, 'America/Havana') from t order by id;
# (F) jump-forward from day boundary, making it invalid
# Here `2023-09-02 23:59:59-04:00` is followed by `2023-09-03 01:00:00-03:00`.
# There is no `2023-09-03 00:00:00-04:00` or `2023-09-03 00:00:00-03:00`.
# PostgreSQL returns `2023-09-03 01:00:00-03:00` but it is hard using `chrono` crate.

query T
select date_trunc('day', '2023-09-03 12:00:00Z'::timestamptz, 'America/Santiago');
Expand Down
44 changes: 26 additions & 18 deletions src/expr/impl/src/scalar/timestamptz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,27 @@ pub fn f64_sec_to_timestamptz(elem: F64) -> Result<Timestamptz> {
pub fn timestamp_at_time_zone(input: Timestamp, time_zone: &str) -> Result<Timestamptz> {
let time_zone = Timestamptz::lookup_time_zone(time_zone).map_err(time_zone_err)?;
// https://www.postgresql.org/docs/current/datetime-invalid-input.html
// Special cases:
// * invalid time during daylight forward
// * use UTC offset before the transition
// * ambiguous time during daylight backward
// * use UTC offset after the transition
let instant_local = match input.0.and_local_timezone(time_zone) {
LocalResult::Single(t) => t,
LocalResult::None => (input.0 + chrono::Duration::hours(1))
.and_local_timezone(time_zone)
.latest()
.ok_or_else(|| ExprError::InvalidParam {
name: "local timestamp",
reason: format!(
"fail to interpret local timestamp \"{}\" in time zone \"{}\"",
input, time_zone
)
.into(),
})?,
// invalid time during daylight forward, use UTC offset before the transition
// we minus 3 hours in naive time first, do the timezone conversion, and add 3 hours back in the UTC timeline.
// This assumes jump forwards are less than 3 hours and there is a single change within this 3-hour window.
// see <https://github.com/risingwavelabs/risingwave/pull/15670#discussion_r1524211006>
LocalResult::None => {
(input.0 - chrono::Duration::hours(3))
.and_local_timezone(time_zone)
.latest()
.ok_or_else(|| ExprError::InvalidParam {
name: "local timestamp",
reason: format!(
"fail to interpret local timestamp \"{}\" in time zone \"{}\"",
input, time_zone
)
.into(),
})?
+ chrono::Duration::hours(3)
}
// ambiguous time during daylight backward, use UTC offset after the transition
LocalResult::Ambiguous(_, latest) => latest,
};
let usec = instant_local.timestamp_micros();
Expand Down Expand Up @@ -237,10 +240,15 @@ mod tests {
#[test]
#[rustfmt::skip]
fn test_time_zone_conversion_daylight_forward() {
// [02:00. 03:00) are invalid
test("2022-03-13 02:00:00", "US/Pacific", "2022-03-13 10:00:00+00:00");
test("2022-03-13 02:59:00", "US/Pacific", "2022-03-13 10:59:00+00:00");
test("2022-03-13 03:00:00", "US/Pacific", "2022-03-13 10:00:00+00:00");
// [02:00. 03:00) are invalid
test("2022-03-27 02:00:00", "europe/zurich", "2022-03-27 01:00:00+00:00");
test("2022-03-27 02:59:00", "europe/zurich", "2022-03-27 01:59:00+00:00");
test("2022-03-27 03:00:00", "europe/zurich", "2022-03-27 01:00:00+00:00");
// [02:00. 02:30) are invalid
test("2023-10-01 02:00:00", "Australia/Lord_Howe", "2023-09-30 15:30:00+00:00");
test("2023-10-01 02:30:00", "Australia/Lord_Howe", "2023-09-30 15:30:00+00:00");

#[track_caller]
fn test(local: &str, zone: &str, instant: &str) {
Expand Down

0 comments on commit babd349

Please sign in to comment.