-
Notifications
You must be signed in to change notification settings - Fork 829
fix: correct off-by-one in toSeconds and wrong day count in Year.days #13566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
46ad680
ded511f
b63b728
5b926ad
da6a251
0321628
1c6ccaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -142,7 +142,7 @@ def createTimeZoneFromTransition (transition : Transition) : TimeZone := | |
| Applies the transition to a Timestamp. | ||
| -/ | ||
| def apply (timestamp : Timestamp) (transition : Transition) : Timestamp := | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is unused. It also makes no sense: a timestamp doesn't have a timezone, so it makes no sense to apply a transition to it. I think it should be removed. |
||
| let offsetInSeconds := transition.localTimeType.gmtOffset.second |>.add transition.localTimeType.gmtOffset.second | ||
| let offsetInSeconds := transition.localTimeType.gmtOffset.second | ||
| timestamp.addSeconds offsetInSeconds | ||
|
|
||
| /-- | ||
|
|
@@ -159,7 +159,7 @@ If the timestamp falls between two transitions, it returns the most recent trans | |
| -/ | ||
| def findTransitionForTimestamp (transitions : Array Transition) (timestamp : Timestamp) : Option Transition := | ||
| if let some idx := findTransitionIndexForTimestamp transitions timestamp | ||
| then transitions[idx - 1]? | ||
| then if idx == 0 then none else transitions[idx - 1]? | ||
| else transitions.back? | ||
|
|
||
| /-- | ||
|
|
@@ -207,6 +207,21 @@ def findLocalTimeTypeForTimestamp (zr : ZoneRules) (timestamp : Timestamp) : Loc | |
| |>.map (·.localTimeType) | ||
| |>.getD zr.initialLocalTimeType | ||
|
|
||
| /-- | ||
| Finds the `LocalTimeType` for a given wall-clock time (seconds since Unix epoch in local time). | ||
| Unlike `findLocalTimeTypeForTimestamp`, this compares each transition's UTC time adjusted by the | ||
| previous offset — necessary when converting local time to UTC. | ||
| -/ | ||
| def findLocalTimeTypeForWallTime (zr : ZoneRules) (wallSecs : Int) : LocalTimeType := | ||
| let (ltt, _) := zr.transitions.foldl (init := (zr.initialLocalTimeType, false)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function becomes clearer and more efficient if you reimplement it with a |
||
| fun (ltt, done) t => | ||
| if done then (ltt, true) | ||
| else | ||
| let localTransitionTime := t.time.add ltt.gmtOffset.second | ||
| if wallSecs < localTransitionTime.val then (ltt, true) | ||
| else (t.localTimeType, false) | ||
| ltt | ||
|
|
||
| /-- | ||
| Find the current `TimeZone` out of a `Transition` in a `ZoneRules` | ||
| -/ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,28 +64,8 @@ Creates a new `ZonedDateTime` out of a `PlainDateTime` and a `ZoneRules`. | |
| @[inline] | ||
| def ofPlainDateTime (pdt : PlainDateTime) (zr : TimeZone.ZoneRules) : ZonedDateTime := | ||
| let tm := pdt.toTimestampAssumingUTC | ||
|
|
||
| let transition := | ||
| let value := tm.toSecondsSinceUnixEpoch | ||
| if let some idx := zr.transitions.findFinIdx? (fun t => t.time.val ≥ value.val) | ||
| then | ||
| let last := zr.transitions[idx.1 - 1] | ||
| let next := zr.transitions[idx] | ||
|
|
||
| let utcNext := next.time.sub last.localTimeType.gmtOffset.second.abs | ||
|
|
||
| if utcNext.val > tm.toSecondsSinceUnixEpoch.val | ||
| then some last | ||
| else some next | ||
|
|
||
| else zr.transitions.back? | ||
|
|
||
| let tz := | ||
| transition | ||
| |>.map (·.localTimeType) | ||
| |>.getD zr.initialLocalTimeType | ||
| |>.getTimeZone | ||
|
|
||
| let ltt := zr.findLocalTimeTypeForWallTime tm.toSecondsSinceUnixEpoch.val | ||
|
Comment on lines
66
to
+67
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still don't like that we're dealing with I would be much much more happy if we could have a new type What do you think? |
||
| let tz := ltt.getTimeZone | ||
| let tm := tm.subSeconds tz.toSeconds | ||
| ZonedDateTime.mk (Thunk.mk fun _ => tm.toPlainDateTimeAssumingUTC.addSeconds tz.toSeconds) tm zr tz | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good improvement to the docstring, and it should also be applied to the analogous functions
toMinutesetc.