summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/times.nim35
-rw-r--r--tests/stdlib/ttime.nim23
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)