diff options
-rw-r--r-- | lib/pure/times.nim | 35 | ||||
-rw-r--r-- | tests/stdlib/ttime.nim | 23 |
2 files changed, 38 insertions, 20 deletions
diff --git a/lib/pure/times.nim b/lib/pure/times.nim index f74003820..cfc39bc55 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -144,8 +144,9 @@ type yearday*: range[0..365] ## The number of days since January 1, ## in the range 0 to 365. ## Always 0 if the target is JS. - isDST*: bool ## Determines whether DST is in effect. Always - ## ``False`` if time is UTC. + isDST*: bool ## Determines whether DST is in effect. + ## Semantically, this adds another negative hour + ## offset to the time in addition to the timezone. timezone*: int ## The offset of the (non-DST) timezone in seconds ## west of UTC. Note that the sign of this number ## is the opposite of the one in a formatted @@ -824,28 +825,32 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) = if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear buf.add(fyear) of "z": - let hours = abs(info.timezone) div secondsInHour - if info.timezone <= 0: buf.add('+') + let + nonDstTz = info.timezone - int(info.isDst) * secondsInHour + hours = abs(nonDstTz) div secondsInHour + if nonDstTz <= 0: buf.add('+') else: buf.add('-') buf.add($hours) of "zz": - let hours = abs(info.timezone) div secondsInHour - if info.timezone <= 0: buf.add('+') + let + nonDstTz = info.timezone - int(info.isDst) * secondsInHour + hours = abs(nonDstTz) div secondsInHour + if nonDstTz <= 0: buf.add('+') else: buf.add('-') if hours < 10: buf.add('0') buf.add($hours) of "zzz": let - hours = abs(info.timezone) div secondsInHour - minutes = (abs(info.timezone) div secondsInMin) mod minutesInHour - if info.timezone <= 0: buf.add('+') + nonDstTz = info.timezone - int(info.isDst) * secondsInHour + hours = abs(nonDstTz) div secondsInHour + minutes = (abs(nonDstTz) div secondsInMin) mod minutesInHour + if nonDstTz <= 0: buf.add('+') else: buf.add('-') if hours < 10: buf.add('0') buf.add($hours) buf.add(':') if minutes < 10: buf.add('0') buf.add($minutes) - of "": discard else: @@ -1000,7 +1005,6 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "M": var pd = parseInt(value[j..j+1], sv) info.month = Month(sv-1) - info.monthday = sv j += pd of "MM": var month = value[j..j+1].parseInt() @@ -1166,6 +1170,7 @@ proc parse*(value, layout: string): TimeInfo = info.hour = 0 info.minute = 0 info.second = 0 + info.isDST = false # DST is never encoded in timestamps. while true: case layout[i] of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',': @@ -1195,14 +1200,6 @@ proc parse*(value, layout: string): TimeInfo = parseToken(info, token, value, j) token = "" - # We are going to process the date to find out if we are in DST, because the - # default based on the current time may be wrong. Calling getLocalTime will - # set this correctly, but the actual time may be offset from when we called - # toTime with a possibly incorrect DST setting, so we are only going to take - # the isDST from this result. - let correctDST = getLocalTime(toTime(info)) - info.isDST = correctDST.isDST - # Now we process it again with the correct isDST to correct things like # weekday and yearday. return getLocalTime(toTime(info)) diff --git a/tests/stdlib/ttime.nim b/tests/stdlib/ttime.nim index c1559ec7a..6d3d7c93a 100644 --- a/tests/stdlib/ttime.nim +++ b/tests/stdlib/ttime.nim @@ -201,4 +201,25 @@ for tz in [ let ti = TimeInfo(monthday: 1, timezone: tz[0]) doAssert ti.format("z") == tz[1] doAssert ti.format("zz") == tz[2] - doAssert ti.format("zzz") == tz[3] \ No newline at end of file + doAssert ti.format("zzz") == tz[3] + +block dstTest: + let nonDst = TimeInfo(year: 2015, month: mJan, monthday: 01, yearday: 0, + weekday: dThu, hour: 00, minute: 00, second: 00, isDST: false, timezone: 0) + var dst = nonDst + dst.isDst = true + # note that both isDST == true and isDST == false are valid here because + # DST is in effect on January 1st in some southern parts of Australia. + + doAssert nonDst.toTime() - dst.toTime() == 3600 + doAssert nonDst.format("z") == "+0" + doAssert dst.format("z") == "+1" + + # parsing will set isDST in relation to the local time. We take a date in + # January and one in July to maximize the probability to hit one date with DST + # and one without on the local machine. However, this is not guaranteed. + let + parsedJul = parse("2016-07-01 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz") + parsedJan = parse("2016-01-05 04:00:00+01:00", "yyyy-MM-ss HH:mm:sszzz") + doAssert toTime(parsedJan) == fromSeconds(1452394800) + doAssert toTime(parsedJul) == fromSeconds(1467342000) |