Skip to content

[fix](nereids) Fix DST spring-forward gap handling in datetime literal timezone conversion#62814

Draft
Mryange wants to merge 1 commit intoapache:masterfrom
Mryange:fix-DST-spring-forward
Draft

[fix](nereids) Fix DST spring-forward gap handling in datetime literal timezone conversion#62814
Mryange wants to merge 1 commit intoapache:masterfrom
Mryange:fix-DST-spring-forward

Conversation

@Mryange
Copy link
Copy Markdown
Contributor

@Mryange Mryange commented Apr 24, 2026

What problem does this PR solve?

Issue Number: N/A

Problem Summary:

When inserting a TIMESTAMPTZ value whose civil time falls in a DST spring-forward gap
(e.g. '2024-03-10 02:30:00 America/New_York' — a time that does not exist because
clocks jump from 02:00 EST to 03:00 EDT), the two FE literal-parsing paths produced
different UTC instants:

Path Input Stored (UTC)
Named-TZ suffix ('... America/New_York') 02:30:00 NY 06:30 UTC
Implicit session TZ (SET time_zone='America/New_York') 02:30:00 07:30 UTC

The correct answer is 07:30 UTC: Java's ZonedDateTime.of() snaps the non-existent
gap time to 03:30 EDT (= 07:30 UTC), but the old code then queried
zoneId.getRules().getOffset(thatTime) which returned the post-snap EDT offset
(-04:00) instead of the pre-gap EST offset (-05:00). Applying this wrong offset
to the original pre-snap civil time 02:30 yielded the incorrect 06:30 UTC.

Root cause

Both parseDateTimeLiteral() and init() in DateTimeLiteral.java used the pattern:

Instant thatTime = ZonedDateTime.of(civil, zoneId).toInstant();   // correct snap
int offset = sessionTz.getOffset(thatTime) - zoneId.getOffset(thatTime); // wrong: uses post-snap offset
// ... apply offset to pre-snap civil fields → wrong result

Fix

Replace the offset-delta arithmetic with a direct zone projection of the correctly
snapped absolute instant:

Instant thatTime = ZonedDateTime.of(civil, zoneId).toInstant(); // correct snap
ZonedDateTime inTarget = thatTime.atZone(targetZone);           // project, don't compute delta
// read fields from inTarget

This applies to both the session-timezone path (for DateTimeLiteral) and the
UTC-storage path (for TimestampTzLiteral).

Changes

  • fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java:
    Fix parseDateTimeLiteral() and init() to convert via Instant.atZone() instead
    of an offset delta.
  • fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimestampTzLiteralTest.java:
    Add testSpringForwardGapConsistency() unit test.
  • regression-test/suites/datatype_p0/timestamptz/test_timestamptz_dst_gap.groovy:
    Add regression test covering both named-TZ and implicit session-TZ paths for a
    spring-forward gap time, asserting they produce the same UTC instant.

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen
Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants