summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/times.nim513
-rw-r--r--tests/js/ttimes.nim13
2 files changed, 266 insertions, 260 deletions
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 2b7c22145..1b088c0ac 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -385,266 +385,6 @@ proc `miliseconds=`*(t: var TimeInterval, milliseconds: int) {.deprecated.} =
   ## version.
   t.milliseconds = milliseconds
 
-when not defined(JS):
-  proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
-    ## gets time after the UNIX epoch (1970) in seconds. It is a float
-    ## because sub-second resolution is likely to be supported (depending
-    ## on the hardware/OS).
-
-  proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
-    ## gets time spent that the CPU spent to run the current process in
-    ## seconds. This may be more useful for benchmarking than ``epochTime``.
-    ## However, it may measure the real time instead (depending on the OS).
-    ## The value of the result has no meaning.
-    ## To generate useful timing values, take the difference between
-    ## the results of two ``cpuTime`` calls:
-    ##
-    ## .. code-block:: nim
-    ##   var t0 = cpuTime()
-    ##   doWork()
-    ##   echo "CPU time [s] ", cpuTime() - t0
-
-when not defined(JS):
-  # C wrapper:
-  when defined(freebsd) or defined(netbsd) or defined(openbsd) or
-      defined(macosx):
-    type
-      StructTM {.importc: "struct tm", final.} = object
-        second {.importc: "tm_sec".},
-          minute {.importc: "tm_min".},
-          hour {.importc: "tm_hour".},
-          monthday {.importc: "tm_mday".},
-          month {.importc: "tm_mon".},
-          year {.importc: "tm_year".},
-          weekday {.importc: "tm_wday".},
-          yearday {.importc: "tm_yday".},
-          isdst {.importc: "tm_isdst".}: cint
-        gmtoff {.importc: "tm_gmtoff".}: clong
-  else:
-    type
-      StructTM {.importc: "struct tm", final.} = object
-        second {.importc: "tm_sec".},
-          minute {.importc: "tm_min".},
-          hour {.importc: "tm_hour".},
-          monthday {.importc: "tm_mday".},
-          month {.importc: "tm_mon".},
-          year {.importc: "tm_year".},
-          weekday {.importc: "tm_wday".},
-          yearday {.importc: "tm_yday".},
-          isdst {.importc: "tm_isdst".}: cint
-  type
-    TimeInfoPtr = ptr StructTM
-    Clock {.importc: "clock_t".} = distinct int
-
-  when not defined(windows):
-    # This is not ANSI C, but common enough
-    proc timegm(t: StructTM): Time {.
-      importc: "timegm", header: "<time.h>", tags: [].}
-
-  proc localtime(timer: ptr Time): TimeInfoPtr {.
-    importc: "localtime", header: "<time.h>", tags: [].}
-  proc gmtime(timer: ptr Time): TimeInfoPtr {.
-    importc: "gmtime", header: "<time.h>", tags: [].}
-  proc timec(timer: ptr Time): Time {.
-    importc: "time", header: "<time.h>", tags: [].}
-  proc mktime(t: StructTM): Time {.
-    importc: "mktime", header: "<time.h>", tags: [].}
-  proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
-  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>",
-    tags: [].}
-
-  var
-    clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
-
-  # our own procs on top of that:
-  proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo =
-    const
-      weekDays: array[0..6, WeekDay] = [
-        dSun, dMon, dTue, dWed, dThu, dFri, dSat]
-    TimeInfo(second: int(tm.second),
-      minute: int(tm.minute),
-      hour: int(tm.hour),
-      monthday: int(tm.monthday),
-      month: Month(tm.month),
-      year: tm.year + 1900'i32,
-      weekday: weekDays[int(tm.weekday)],
-      yearday: int(tm.yearday),
-      isDST: tm.isdst > 0,
-      timezone: if local: getTimezone() else: 0
-    )
-
-
-  proc timeInfoToTM(t: TimeInfo): StructTM =
-    const
-      weekDays: array[WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
-    result.second = t.second
-    result.minute = t.minute
-    result.hour = t.hour
-    result.monthday = t.monthday
-    result.month = ord(t.month)
-    result.year = cint(t.year - 1900)
-    result.weekday = weekDays[t.weekday]
-    result.yearday = t.yearday
-    result.isdst = if t.isDST: 1 else: 0
-
-  when not defined(useNimRtl):
-    proc `-` (a, b: Time): int64 =
-      return toBiggestInt(difftime(a, b))
-
-  proc getStartMilsecs(): int =
-    #echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock())
-    #return getClock() div (clocksPerSec div 1000)
-    when defined(macosx):
-      result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
-    else:
-      result = int(getClock()) div (clocksPerSec div 1000)
-    when false:
-      var a: Timeval
-      posix_gettimeofday(a)
-      result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64
-      #echo "result: ", result
-
-  proc getTime(): Time = return timec(nil)
-  proc getLocalTime(t: Time): TimeInfo =
-    var a = t
-    let lt = localtime(addr(a))
-    assert(not lt.isNil)
-    result = tmToTimeInfo(lt[], true)
-    # copying is needed anyway to provide reentrancity; thus
-    # the conversion is not expensive
-
-  proc getGMTime(t: Time): TimeInfo =
-    var a = t
-    result = tmToTimeInfo(gmtime(addr(a))[], false)
-    # copying is needed anyway to provide reentrancity; thus
-    # the conversion is not expensive
-
-  proc toTime(timeInfo: TimeInfo): Time =
-    var cTimeInfo = timeInfo # for C++ we have to make a copy
-    # because the header of mktime is broken in my version of libc
-
-    result = mktime(timeInfoToTM(cTimeInfo))
-    # mktime is defined to interpret the input as local time. As timeInfoToTM
-    # does ignore the timezone, we need to adjust this here.
-    result = Time(TimeImpl(result) - getTimezone() + timeInfo.timezone)
-
-  proc timeInfoToTime(timeInfo: TimeInfo): Time = toTime(timeInfo)
-
-  const
-    epochDiff = 116444736000000000'i64
-    rateDiff = 10000000'i64 # 100 nsecs
-
-  proc unixTimeToWinTime*(t: Time): int64 =
-    ## converts a UNIX `Time` (``time_t``) to a Windows file time
-    result = int64(t) * rateDiff + epochDiff
-
-  proc winTimeToUnixTime*(t: int64): Time =
-    ## converts a Windows time to a UNIX `Time` (``time_t``)
-    result = Time((t - epochDiff) div rateDiff)
-
-  proc getTimezone(): int =
-    when defined(freebsd) or defined(netbsd) or defined(openbsd):
-      var a = timec(nil)
-      let lt = localtime(addr(a))
-      # BSD stores in `gmtoff` offset east of UTC in seconds,
-      # but posix systems using west of UTC in seconds
-      return -(lt.gmtoff)
-    else:
-      return timezone
-
-  proc fromSeconds(since1970: float): Time = Time(since1970)
-
-  proc toSeconds(time: Time): float = float(time)
-
-  when not defined(useNimRtl):
-    proc epochTime(): float =
-      when defined(posix):
-        var a: Timeval
-        posix_gettimeofday(a)
-        result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
-      elif defined(windows):
-        var f: winlean.FILETIME
-        getSystemTimeAsFileTime(f)
-        var i64 = rdFileTime(f) - epochDiff
-        var secs = i64 div rateDiff
-        var subsecs = i64 mod rateDiff
-        result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
-      else:
-        {.error: "unknown OS".}
-
-    proc cpuTime(): float =
-      result = toFloat(int(getClock())) / toFloat(clocksPerSec)
-
-elif defined(JS):
-  proc newDate(): Time {.importc: "new Date".}
-  proc internGetTime(): Time {.importc: "new Date", tags: [].}
-
-  proc newDate(value: float): Time {.importc: "new Date".}
-  proc newDate(value: string): Time {.importc: "new Date".}
-  proc getTime(): Time =
-    # Warning: This is something different in JS.
-    return newDate()
-
-  const
-    weekDays: array[0..6, WeekDay] = [
-      dSun, dMon, dTue, dWed, dThu, dFri, dSat]
-
-  proc getLocalTime(t: Time): TimeInfo =
-    result.second = t.getSeconds()
-    result.minute = t.getMinutes()
-    result.hour = t.getHours()
-    result.monthday = t.getDate()
-    result.month = Month(t.getMonth())
-    result.year = t.getFullYear()
-    result.weekday = weekDays[t.getDay()]
-    result.timezone = getTimezone()
-
-    result.yearday = result.monthday - 1
-    for month in mJan..<result.month:
-      result.yearday += getDaysInMonth(month, result.year)
-
-  proc getGMTime(t: Time): TimeInfo =
-    result.second = t.getUTCSeconds()
-    result.minute = t.getUTCMinutes()
-    result.hour = t.getUTCHours()
-    result.monthday = t.getUTCDate()
-    result.month = Month(t.getUTCMonth())
-    result.year = t.getUTCFullYear()
-    result.weekday = weekDays[t.getUTCDay()]
-
-    result.yearday = result.monthday - 1
-    for month in mJan..<result.month:
-      result.yearday += getDaysInMonth(month, result.year)
-
-  proc timeInfoToTime(timeInfo: TimeInfo): Time = toTime(timeInfo)
-
-  proc toTime*(timeInfo: TimeInfo): Time =
-    result = internGetTime()
-    result.setMinutes(timeInfo.minute)
-    result.setHours(timeInfo.hour)
-    result.setMonth(ord(timeInfo.month))
-    result.setFullYear(timeInfo.year)
-    result.setDate(timeInfo.monthday)
-    result.setSeconds(timeInfo.second + timeInfo.timezone)
-
-  proc `-` (a, b: Time): int64 =
-    return a.getTime() - b.getTime()
-
-  var
-    startMilsecs = getTime()
-
-  proc getStartMilsecs(): int =
-    ## get the milliseconds from the start of the program
-    return int(getTime() - startMilsecs)
-
-  proc fromSeconds(since1970: float): Time = result = newDate(since1970 * 1000)
-
-  proc toSeconds(time: Time): float = result = time.getTime() / 1000
-
-  proc getTimezone(): int = result = newDate().getTimezoneOffset() * 60
-
-  proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
-
 proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
   ## gets the current date as a string of the format ``YYYY-MM-DD``.
   var ti = getLocalTime(getTime())
@@ -1339,6 +1079,259 @@ proc toTimeInterval*(t: Time): TimeInterval =
   var tInfo = t.getLocalTime()
   initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
 
+when not defined(JS):
+  proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
+    ## gets time after the UNIX epoch (1970) in seconds. It is a float
+    ## because sub-second resolution is likely to be supported (depending
+    ## on the hardware/OS).
+
+  proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
+    ## gets time spent that the CPU spent to run the current process in
+    ## seconds. This may be more useful for benchmarking than ``epochTime``.
+    ## However, it may measure the real time instead (depending on the OS).
+    ## The value of the result has no meaning.
+    ## To generate useful timing values, take the difference between
+    ## the results of two ``cpuTime`` calls:
+    ##
+    ## .. code-block:: nim
+    ##   var t0 = cpuTime()
+    ##   doWork()
+    ##   echo "CPU time [s] ", cpuTime() - t0
+
+when not defined(JS):
+  # C wrapper:
+  when defined(freebsd) or defined(netbsd) or defined(openbsd) or
+      defined(macosx):
+    type
+      StructTM {.importc: "struct tm", final.} = object
+        second {.importc: "tm_sec".},
+          minute {.importc: "tm_min".},
+          hour {.importc: "tm_hour".},
+          monthday {.importc: "tm_mday".},
+          month {.importc: "tm_mon".},
+          year {.importc: "tm_year".},
+          weekday {.importc: "tm_wday".},
+          yearday {.importc: "tm_yday".},
+          isdst {.importc: "tm_isdst".}: cint
+        gmtoff {.importc: "tm_gmtoff".}: clong
+  else:
+    type
+      StructTM {.importc: "struct tm", final.} = object
+        second {.importc: "tm_sec".},
+          minute {.importc: "tm_min".},
+          hour {.importc: "tm_hour".},
+          monthday {.importc: "tm_mday".},
+          month {.importc: "tm_mon".},
+          year {.importc: "tm_year".},
+          weekday {.importc: "tm_wday".},
+          yearday {.importc: "tm_yday".},
+          isdst {.importc: "tm_isdst".}: cint
+  type
+    TimeInfoPtr = ptr StructTM
+    Clock {.importc: "clock_t".} = distinct int
+
+  when not defined(windows):
+    # This is not ANSI C, but common enough
+    proc timegm(t: StructTM): Time {.
+      importc: "timegm", header: "<time.h>", tags: [].}
+
+  proc localtime(timer: ptr Time): TimeInfoPtr {.
+    importc: "localtime", header: "<time.h>", tags: [].}
+  proc gmtime(timer: ptr Time): TimeInfoPtr {.
+    importc: "gmtime", header: "<time.h>", tags: [].}
+  proc timec(timer: ptr Time): Time {.
+    importc: "time", header: "<time.h>", tags: [].}
+  proc mktime(t: StructTM): Time {.
+    importc: "mktime", header: "<time.h>", tags: [].}
+  proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
+  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>",
+    tags: [].}
+
+  var
+    clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
+
+  # our own procs on top of that:
+  proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo =
+    const
+      weekDays: array[0..6, WeekDay] = [
+        dSun, dMon, dTue, dWed, dThu, dFri, dSat]
+    TimeInfo(second: int(tm.second),
+      minute: int(tm.minute),
+      hour: int(tm.hour),
+      monthday: int(tm.monthday),
+      month: Month(tm.month),
+      year: tm.year + 1900'i32,
+      weekday: weekDays[int(tm.weekday)],
+      yearday: int(tm.yearday),
+      isDST: tm.isdst > 0,
+      timezone: if local: getTimezone() else: 0
+    )
+
+
+  proc timeInfoToTM(t: TimeInfo): StructTM =
+    const
+      weekDays: array[WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
+    result.second = t.second
+    result.minute = t.minute
+    result.hour = t.hour
+    result.monthday = t.monthday
+    result.month = ord(t.month)
+    result.year = cint(t.year - 1900)
+    result.weekday = weekDays[t.weekday]
+    result.yearday = t.yearday
+    result.isdst = if t.isDST: 1 else: 0
+
+  when not defined(useNimRtl):
+    proc `-` (a, b: Time): int64 =
+      return toBiggestInt(difftime(a, b))
+
+  proc getStartMilsecs(): int =
+    #echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock())
+    #return getClock() div (clocksPerSec div 1000)
+    when defined(macosx):
+      result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
+    else:
+      result = int(getClock()) div (clocksPerSec div 1000)
+    when false:
+      var a: Timeval
+      posix_gettimeofday(a)
+      result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64
+      #echo "result: ", result
+
+  proc getTime(): Time = return timec(nil)
+  proc getLocalTime(t: Time): TimeInfo =
+    var a = t
+    let lt = localtime(addr(a))
+    assert(not lt.isNil)
+    result = tmToTimeInfo(lt[], true)
+    # copying is needed anyway to provide reentrancity; thus
+    # the conversion is not expensive
+
+  proc getGMTime(t: Time): TimeInfo =
+    var a = t
+    result = tmToTimeInfo(gmtime(addr(a))[], false)
+    # copying is needed anyway to provide reentrancity; thus
+    # the conversion is not expensive
+
+  proc toTime(timeInfo: TimeInfo): Time =
+    var cTimeInfo = timeInfo # for C++ we have to make a copy
+    # because the header of mktime is broken in my version of libc
+
+    result = mktime(timeInfoToTM(cTimeInfo))
+    # mktime is defined to interpret the input as local time. As timeInfoToTM
+    # does ignore the timezone, we need to adjust this here.
+    result = Time(TimeImpl(result) - getTimezone() + timeInfo.timezone)
+
+  proc timeInfoToTime(timeInfo: TimeInfo): Time = toTime(timeInfo)
+
+  const
+    epochDiff = 116444736000000000'i64
+    rateDiff = 10000000'i64 # 100 nsecs
+
+  proc unixTimeToWinTime*(t: Time): int64 =
+    ## converts a UNIX `Time` (``time_t``) to a Windows file time
+    result = int64(t) * rateDiff + epochDiff
+
+  proc winTimeToUnixTime*(t: int64): Time =
+    ## converts a Windows time to a UNIX `Time` (``time_t``)
+    result = Time((t - epochDiff) div rateDiff)
+
+  proc getTimezone(): int =
+    when defined(freebsd) or defined(netbsd) or defined(openbsd):
+      var a = timec(nil)
+      let lt = localtime(addr(a))
+      # BSD stores in `gmtoff` offset east of UTC in seconds,
+      # but posix systems using west of UTC in seconds
+      return -(lt.gmtoff)
+    else:
+      return timezone
+
+  proc fromSeconds(since1970: float): Time = Time(since1970)
+
+  proc toSeconds(time: Time): float = float(time)
+
+  when not defined(useNimRtl):
+    proc epochTime(): float =
+      when defined(posix):
+        var a: Timeval
+        posix_gettimeofday(a)
+        result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
+      elif defined(windows):
+        var f: winlean.FILETIME
+        getSystemTimeAsFileTime(f)
+        var i64 = rdFileTime(f) - epochDiff
+        var secs = i64 div rateDiff
+        var subsecs = i64 mod rateDiff
+        result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
+      else:
+        {.error: "unknown OS".}
+
+    proc cpuTime(): float =
+      result = toFloat(int(getClock())) / toFloat(clocksPerSec)
+
+elif defined(JS):
+  proc newDate(): Time {.importc: "new Date".}
+  proc internGetTime(): Time {.importc: "new Date", tags: [].}
+
+  proc newDate(value: float): Time {.importc: "new Date".}
+  proc newDate(value: cstring): Time {.importc: "new Date".}
+  proc getTime(): Time =
+    # Warning: This is something different in JS.
+    return newDate()
+
+  const
+    weekDays: array[0..6, WeekDay] = [
+      dSun, dMon, dTue, dWed, dThu, dFri, dSat]
+
+  proc getLocalTime(t: Time): TimeInfo =
+    result.second = t.getSeconds()
+    result.minute = t.getMinutes()
+    result.hour = t.getHours()
+    result.monthday = t.getDate()
+    result.month = Month(t.getMonth())
+    result.year = t.getFullYear()
+    result.weekday = weekDays[t.getDay()]
+    result.timezone = getTimezone()
+
+    result.yearday = result.monthday - 1
+    for month in mJan..<result.month:
+      result.yearday += getDaysInMonth(month, result.year)
+
+  proc getGMTime(t: Time): TimeInfo =
+    result.second = t.getUTCSeconds()
+    result.minute = t.getUTCMinutes()
+    result.hour = t.getUTCHours()
+    result.monthday = t.getUTCDate()
+    result.month = Month(t.getUTCMonth())
+    result.year = t.getUTCFullYear()
+    result.weekday = weekDays[t.getUTCDay()]
+
+    result.yearday = result.monthday - 1
+    for month in mJan..<result.month:
+      result.yearday += getDaysInMonth(month, result.year)
+
+  proc timeInfoToTime(timeInfo: TimeInfo): Time = toTime(timeInfo)
+
+  proc toTime*(timeInfo: TimeInfo): Time = newDate($timeInfo)
+
+  proc `-` (a, b: Time): int64 =
+    return a.getTime() - b.getTime()
+
+  var
+    startMilsecs = getTime()
+
+  proc getStartMilsecs(): int =
+    ## get the milliseconds from the start of the program
+    return int(getTime() - startMilsecs)
+
+  proc fromSeconds(since1970: float): Time = result = newDate(since1970 * 1000)
+
+  proc toSeconds(time: Time): float = result = time.getTime() / 1000
+
+  proc getTimezone(): int = result = newDate().getTimezoneOffset() * 60
+
+  proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
+
 
 when isMainModule:
   # this is testing non-exported function
diff --git a/tests/js/ttimes.nim b/tests/js/ttimes.nim
index 644e9670a..20ba14245 100644
--- a/tests/js/ttimes.nim
+++ b/tests/js/ttimes.nim
@@ -11,3 +11,16 @@ import times
 block yeardayTest:
   # check if yearday attribute is properly set on TimeInfo creation
   doAssert fromSeconds(2147483647).getGMTime().yearday == 18
+
+block localTimezoneTest:
+  # check if timezone is properly set during Time to TimeInfo conversion
+  doAssert fromSeconds(2147483647).getLocalTime().timezone == getTimezone()
+
+block timestampPersistenceTest:
+  # check if timestamp persists during TimeInfo to Time conversion
+  const
+    timeString = "2017-03-21T12:34:56+03:00"
+    timeStringGmt = "2017-03-21T09:34:56+00:00"
+    fmt = "yyyy-MM-dd'T'HH:mm:sszzz"
+
+  doAssert $timeString.parse(fmt).toTime().getGMTime() == timeStringGmt