Fix shift() producing wrong results across DST transitions#1253
Open
worksbyfriday wants to merge 1 commit intoarrow-py:masterfrom
Open
Fix shift() producing wrong results across DST transitions#1253worksbyfriday wants to merge 1 commit intoarrow-py:masterfrom
worksbyfriday wants to merge 1 commit intoarrow-py:masterfrom
Conversation
When shifting by absolute time units (hours, minutes, seconds, microseconds) across DST boundaries, the result was off by the DST offset because relativedelta uses wall-clock arithmetic. For example, shift(hours=10) starting at 18:30 CST across a spring-forward boundary gave 04:30 CDT (9 real hours) instead of 05:30 CDT (10 real hours). Fix: separate absolute time units from calendar units. Calendar units (years, months, weeks, days) continue to use relativedelta for wall-clock semantics. Absolute units are now added via UTC conversion, ensuring they reflect real elapsed time regardless of DST transitions. Fixes arrow-py#1209 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
shift(hours=N)across DST spring-forward and fall-back boundaries produces incorrect results — the elapsed time is off by the DST offset.Root cause:
relativedeltauses wall-clock arithmetic. Addinghours=10means "add 10 to the local hour," not "advance 10 real hours." When crossing a DST transition, these diverge.Example from #1209:
Fix: Separate kwargs into calendar units (years, months, weeks, days) and absolute units (hours, minutes, seconds, microseconds). Calendar units use
relativedelta(wall-clock semantics). Absolute units are added via UTC conversion (real elapsed time).This matches the semantics users expect:
shift(days=1)preserves the local time, whileshift(hours=24)advances exactly 24 real hours — which may or may not preserve the local time depending on DST.Changes
arrow/arrow.py: Split absolute time kwargs from calendar kwargs; apply absolute units via UTCtests/test_arrow.py: Addedtest_shift_dst_absolute_timecovering spring-forward, fall-back, and mixed calendar+absolute shifts. Updated existingtest_shift_negative_imaginaryand imaginary-check tests to reflect correct absolute-time expectations.CHANGELOG.rst: Added entryTest plan
shift(days=1, hours=3)applies calendar then absolutecheck_imaginarystill works for calendar shiftsFixes #1209
🤖 Generated with Claude Code