Skip to content

Commit 2f3f9de

Browse files
committed
Take into account comments, and finish correctLocaleDefault
1 parent 566159e commit 2f3f9de

File tree

1 file changed

+49
-49
lines changed

1 file changed

+49
-49
lines changed

0000-utc-handling.md

+49-49
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Intro
44

5+
**NOTE**: In the following document, DST refers to time shifts happening in
6+
different timezones, not necesserily the ones occuring periodically for
7+
"daylight-saving-time".
8+
59
Datetime handling is relatively straight forward for UTC, but can get messy
610
around DST (Daylight Savings Time), when the local clock shifts forwards or
711
backwards one hour. During DST it's possible that a particular local time is
@@ -30,15 +34,15 @@ Of course local correct operations sometimes will hit an invalid or ambiguous
3034
local date. There are a few available options for each case.
3135

3236
* for invalid dates:
33-
* jump forward by one (or more) hours until the time is valid
34-
* jump backward by one (or more) hours until the time is valid
35-
* jump forward to first valid time (might not be whole hours)
36-
* jump backward to first valid time (might not be whole hours)
37+
* jump forward by the size of the gap (default)
38+
* jump backward by the size of the gap
39+
* jump forward to first valid time (might not be size of gap)
40+
* jump backward to first valid time (might not be size of gap)
3741
* declare the date as invalid
3842

3943
* for ambiguous dates:
44+
* pick past offset (the one that was present before DST) (default)
4045
* pick future offset (the one that continues after DST)
41-
* pick past offset (the one that was present before DST)
4246
* pick current offset (in case this operation changes from old to new date,
4347
the old date's offset could be used, if its one of the two alternatives
4448
-- so this *option* is only best effort and needs to be backed up by
@@ -53,29 +57,23 @@ operations. All these choices could be configurable.
5357

5458
* Create from local time - given year, month, day, hour, min, sec in local
5559
time, construct a moment. Note that the given time might be invalid or
56-
ambiguous. Invalid - jump forward by whole hours to first valid local time.
57-
Ambiguous - pick the offset that continues in the future.
60+
ambiguous. Use the default operations for invalid/ambiguous.
5861
* Add/Subtract
5962
* add/subtract smaller units (hour or less) - these should be *UTC correct*
6063
* add/subtract bigger units (day or more) - these should be *local correct*
64+
To put it differently, they should behave like a Set operation.
6165
The idea is that 1st May 12:34 + 15 days should be 16 May 12:34 (if
62-
possible), no matter what DST happened from 1st to 15th of May. If the
63-
time is invalid, jump forward (by whole hour) to valid; if ambiguous pick
64-
future. (For subtract jump backwards and pick past).
66+
possible), no matter what DST happened from 1st to 15th of May. Use
67+
default operations for invalid/ambiguous (same as set, create).
6568
* Set one or several units - set is very similar to create (but instead of
66-
specifying all units, only the different ones are specified).
67-
* set smaller units (minute or less) - these should be *UTC correct*. That
68-
is, the set acts as an add/subtract depending on the current value. So if
69-
the minute is now 15, a set to 45 means add 30 minutes (check
70-
add/subtract above).
71-
* set bigger units (hour or more) - these should be *local correct*. So,
72-
again it acts as add/subtract depending on current value, and tries to be
73-
local correct.
69+
specifying all units, only the different ones are specified). Use default
70+
operations for invaid/ambiguous moments, resulting from a set.
7471
* StartOf/EndOf
75-
* statof 'day' - in case the start of day is invalid - jump to first valid
76-
local time of today (not whole hours), in case its ambiguous - pick the
77-
future one
78-
* endof 'day' - same idea as start of but in reverse :)
72+
* statof UNIT - in case the start of UNIT is invalid - jump to first valid
73+
local time of the UNIT (that might not be the gap), in case its ambiguous
74+
- pick the past one (that is the default).
75+
* endof UNIT - this should just use startof UNIT - 1ms (UTC correct
76+
-1ms).
7977
* change timezone while keeping the local time - same idea applies as creating
8078
local time from components
8179

@@ -111,44 +109,46 @@ universally recognized way of keeping local time, but I'll still use it here
111109
because its one number, instead of 2 or more). Note that it could be invalid or
112110
ambiguous.
113111

114-
* `localToOffsets(lts)` -- we'll define a function that returns all offsets of
115-
a given local timestamp.
112+
* `correctLocalDefault(lts)` -- return [new\_lts, offset], new\_lts might
113+
differ from lts if lts is invalid.
116114

117115
```javascript
118-
function localToOffsets(lts) {
116+
function correctLocaleDefault(lts) {
119117
var res = []
120118
var of1 = getOffsetFromUTC(lts) // we treat local timestamp as unix to get
121119
// a ballbpark estimate
122120
var of2 = getOffsetFromUTC(lts - of1) // adjust local by probable offset
123121
if (of1 == of2) {
124-
// (lts, of1) is valid
125-
res.push(of1)
126-
} else {
127-
var of3 = getOffsetFromUTC(lts - of2)
128-
if (of3 == of2) {
129-
// (lts, of2) is valid
130-
res.push(of2)
122+
// (lts, of1) is valid, but could be ambigous (second)
123+
of3 = getOffsetFromUTC(lts - of1 - 6h); // subtract 6h to see if
124+
// we're near DST
125+
if (of1 == of3) {
126+
return [lts, of1];
127+
} else if (getOffsetFromUTC(lts - of3) == of3) {
128+
// ambiguous, variants are [lts, of3], [lts, of1], of3 being
129+
// the previous
130+
return [lts, of3];
131131
} else {
132-
// lts is invalid
132+
// there was DST shortly before [lts, of1], but it fully passed
133+
return [lts, of1];
133134
}
134-
}
135-
136-
if (res.length == 0) {
137-
// invalid
138-
return res;
139135
} else {
140-
var of = res[0];
141-
// NOTE: This is heruistic, so might not work in all cases.
142-
// check the offsets of lts-of+1h and lts-of-1h
143-
var of4 = getOffsetFromUTC(lts-of-1h)
144-
var of5 = getOffsetFromUTC(lts-of+1h)
145-
146-
if (of4 == of+1h) {
147-
res.push(of4)
148-
} else if (of5 == of-1h) {
149-
res.push(of5)
136+
// we try a second time, this could happen around invalid time
137+
var of3 = getOffsetFromUTC(lts - of2);
138+
if (of3 == of2) {
139+
return [lts, of2]
140+
} else {
141+
// invalid time!
142+
if (of2 > of3) {
143+
var tmp = of2; of2 = of3; of3 = tmp;
144+
}
145+
var dstGap = of3 - of2;
146+
if (getOffsetFromUTC(lts + dstGap - of3) == of3) {
147+
return [lts, of3];
148+
} else {
149+
throw new Error("should never happen (test)");
150+
}
150151
}
151-
return res;
152152
}
153153
}
154154
```

0 commit comments

Comments
 (0)