parent
7dcf435b4b
commit
1d93991929
3 changed files with 75 additions and 151 deletions
|
|
@ -423,18 +423,14 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} =
|
||||||
## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``).
|
## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``).
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert fromUnix(0).toUnix() == 0
|
doAssert fromUnix(0).toUnix() == 0
|
||||||
|
|
||||||
t.seconds
|
t.seconds
|
||||||
|
|
||||||
proc fromWinTime*(win: int64): Time =
|
proc fromWinTime*(win: int64): Time =
|
||||||
## Convert a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``)
|
## Convert a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``)
|
||||||
## to a ``Time``.
|
## to a ``Time``.
|
||||||
let hnsecsSinceEpoch = (win - epochDiff)
|
const hnsecsPerSec = convert(Seconds, Nanoseconds, 1) div 100
|
||||||
var seconds = hnsecsSinceEpoch div rateDiff
|
let nanos = floorMod(win, hnsecsPerSec) * 100
|
||||||
var nanos = ((hnsecsSinceEpoch mod rateDiff) * 100).int
|
let seconds = floorDiv(win - epochDiff, hnsecsPerSec)
|
||||||
if nanos < 0:
|
|
||||||
nanos += convert(Seconds, Nanoseconds, 1)
|
|
||||||
seconds -= 1
|
|
||||||
result = initTime(seconds, nanos)
|
result = initTime(seconds, nanos)
|
||||||
|
|
||||||
proc toWinTime*(t: Time): int64 =
|
proc toWinTime*(t: Time): int64 =
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
discard """
|
|
||||||
action: run
|
|
||||||
"""
|
|
||||||
|
|
||||||
import times
|
|
||||||
|
|
||||||
# $ date --date='@2147483647'
|
|
||||||
# Tue 19 Jan 03:14:07 GMT 2038
|
|
||||||
|
|
||||||
block yeardayTest:
|
|
||||||
doAssert fromUnix(2147483647).utc.yearday == 18
|
|
||||||
|
|
||||||
block localTime:
|
|
||||||
var local = now()
|
|
||||||
let utc = local.utc
|
|
||||||
doAssert local.toTime == utc.toTime
|
|
||||||
|
|
||||||
let a = fromUnix(1_000_000_000)
|
|
||||||
let b = fromUnix(1_500_000_000)
|
|
||||||
doAssert b - a == initDuration(seconds = 500_000_000)
|
|
||||||
|
|
||||||
# Because we can't change the timezone JS uses, we define a simple static timezone for testing.
|
|
||||||
|
|
||||||
proc zonedTimeFromTime(time: Time): ZonedTime =
|
|
||||||
result.utcOffset = -7200
|
|
||||||
result.isDst = false
|
|
||||||
result.time = time
|
|
||||||
|
|
||||||
proc zonedTimeFromAdjTime(adjTime: Time): ZonedTIme =
|
|
||||||
result.utcOffset = -7200
|
|
||||||
result.isDst = false
|
|
||||||
result.time = adjTime + initDuration(seconds = -7200)
|
|
||||||
|
|
||||||
let utcPlus2 = newTimezone("", zonedTimeFromTime, zonedTimeFromAdjTime)
|
|
||||||
|
|
||||||
block timezoneTests:
|
|
||||||
let dt = initDateTime(01, mJan, 2017, 12, 00, 00, utcPlus2)
|
|
||||||
doAssert $dt == "2017-01-01T12:00:00+02:00"
|
|
||||||
doAssert $dt.utc == "2017-01-01T10:00:00Z"
|
|
||||||
doAssert $dt.utc.inZone(utcPlus2) == $dt
|
|
||||||
|
|
||||||
doAssert $initDateTime(01, mJan, 1911, 12, 00, 00, utc()) == "1911-01-01T12:00:00Z"
|
|
||||||
doAssert $initDateTime(01, mJan, 0023, 12, 00, 00, utc()) == "0023-01-01T12:00:00Z"
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
# test the new time module
|
|
||||||
discard """
|
discard """
|
||||||
file: "ttimes.nim"
|
file: "ttimes.nim"
|
||||||
|
target: "c js"
|
||||||
output: '''[Suite] ttimes
|
output: '''[Suite] ttimes
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import
|
import times, strutils, unittest
|
||||||
times, os, strutils, unittest
|
|
||||||
|
when not defined(js):
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Normally testament configures unittest with environment variables,
|
||||||
|
# but that doesn't work for the JS target. So instead we must set the correct
|
||||||
|
# settings here.
|
||||||
|
addOutputFormatter(
|
||||||
|
newConsoleOutputFormatter(PRINT_FAILURES, colorOutput = false))
|
||||||
|
|
||||||
proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} =
|
proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} =
|
||||||
let offset = hours * 3600 + minutes * 60 + seconds
|
let offset = hours * 3600 + minutes * 60 + seconds
|
||||||
|
|
@ -23,99 +31,12 @@ proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} =
|
||||||
|
|
||||||
newTimezone("", zonedTimeFromTime, zonedTImeFromAdjTime)
|
newTimezone("", zonedTimeFromTime, zonedTImeFromAdjTime)
|
||||||
|
|
||||||
# $ date --date='@2147483647'
|
|
||||||
# Tue 19 Jan 03:14:07 GMT 2038
|
|
||||||
|
|
||||||
proc checkFormat(t: DateTime, format, expected: string) =
|
|
||||||
let actual = t.format(format)
|
|
||||||
if actual != expected:
|
|
||||||
echo "Formatting failure!"
|
|
||||||
echo "expected: ", expected
|
|
||||||
echo "actual : ", actual
|
|
||||||
doAssert false
|
|
||||||
|
|
||||||
let t2 = fromUnix(160070789).utc() # Mon 27 Jan 16:06:29 GMT 1975
|
|
||||||
t2.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
|
|
||||||
" ss t tt y yy yyy yyyy yyyyy z zz zzz",
|
|
||||||
"27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 Z Z Z")
|
|
||||||
|
|
||||||
var t4 = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997
|
|
||||||
t4.checkFormat("M MM MMM MMMM", "10 10 Oct October")
|
|
||||||
|
|
||||||
# Interval tests
|
|
||||||
(t4 - initTimeInterval(years = 2)).checkFormat("yyyy", "1995")
|
|
||||||
(t4 - initTimeInterval(years = 7, minutes = 34, seconds = 24)).checkFormat("yyyy mm ss", "1990 24 10")
|
|
||||||
|
|
||||||
# checking dayOfWeek matches known days
|
|
||||||
doAssert getDayOfWeek(01, mJan, 0000) == dSat
|
|
||||||
doAssert getDayOfWeek(01, mJan, -0023) == dSat
|
|
||||||
doAssert getDayOfWeek(21, mSep, 1900) == dFri
|
|
||||||
doAssert getDayOfWeek(01, mJan, 1970) == dThu
|
|
||||||
doAssert getDayOfWeek(21, mSep, 1970) == dMon
|
|
||||||
doAssert getDayOfWeek(01, mJan, 2000) == dSat
|
|
||||||
doAssert getDayOfWeek(01, mJan, 2021) == dFri
|
|
||||||
|
|
||||||
# toUnix tests with GM timezone
|
|
||||||
let t4L = fromUnix(876124714).utc
|
|
||||||
doAssert toUnix(toTime(t4L)) == 876124714
|
|
||||||
doAssert toUnix(toTime(t4L)) + t4L.utcOffset == toUnix(toTime(t4))
|
|
||||||
|
|
||||||
# adding intervals
|
|
||||||
var
|
|
||||||
a1L = toUnix(toTime(t4L + initTimeInterval(hours = 1))) + t4L.utcOffset
|
|
||||||
a1G = toUnix(toTime(t4)) + 60 * 60
|
|
||||||
doAssert a1L == a1G
|
|
||||||
|
|
||||||
# subtracting intervals
|
|
||||||
a1L = toUnix(toTime(t4L - initTimeInterval(hours = 1))) + t4L.utcOffset
|
|
||||||
a1G = toUnix(toTime(t4)) - (60 * 60)
|
|
||||||
doAssert a1L == a1G
|
|
||||||
|
|
||||||
# Comparison between Time objects should be detected by compiler
|
|
||||||
# as 'noSideEffect'.
|
|
||||||
proc cmpTimeNoSideEffect(t1: Time, t2: Time): bool {.noSideEffect.} =
|
|
||||||
result = t1 == t2
|
|
||||||
doAssert cmpTimeNoSideEffect(0.fromUnix, 0.fromUnix)
|
|
||||||
# Additionally `==` generic for seq[T] has explicit 'noSideEffect' pragma
|
|
||||||
# so we can check above condition by comparing seq[Time] sequences
|
|
||||||
let seqA: seq[Time] = @[]
|
|
||||||
let seqB: seq[Time] = @[]
|
|
||||||
doAssert seqA == seqB
|
|
||||||
|
|
||||||
for tz in [
|
|
||||||
(staticTz(seconds = 0), "+0", "+00", "+00:00"), # UTC
|
|
||||||
(staticTz(seconds = -3600), "+1", "+01", "+01:00"), # CET
|
|
||||||
(staticTz(seconds = -39600), "+11", "+11", "+11:00"), # two digits
|
|
||||||
(staticTz(seconds = -1800), "+0", "+00", "+00:30"), # half an hour
|
|
||||||
(staticTz(seconds = 7200), "-2", "-02", "-02:00"), # positive
|
|
||||||
(staticTz(seconds = 38700), "-10", "-10", "-10:45")]: # positive with three quaters hour
|
|
||||||
let dt = initDateTime(1, mJan, 2000, 00, 00, 00, tz[0])
|
|
||||||
doAssert dt.format("z") == tz[1]
|
|
||||||
doAssert dt.format("zz") == tz[2]
|
|
||||||
doAssert dt.format("zzz") == tz[3]
|
|
||||||
|
|
||||||
block countLeapYears:
|
|
||||||
# 1920, 2004 and 2020 are leap years, and should be counted starting at the following year
|
|
||||||
doAssert countLeapYears(1920) + 1 == countLeapYears(1921)
|
|
||||||
doAssert countLeapYears(2004) + 1 == countLeapYears(2005)
|
|
||||||
doAssert countLeapYears(2020) + 1 == countLeapYears(2021)
|
|
||||||
|
|
||||||
block timezoneConversion:
|
|
||||||
var l = now()
|
|
||||||
let u = l.utc
|
|
||||||
l = u.local
|
|
||||||
|
|
||||||
doAssert l.timezone == local()
|
|
||||||
doAssert u.timezone == utc()
|
|
||||||
|
|
||||||
template parseTest(s, f, sExpected: string, ydExpected: int) =
|
template parseTest(s, f, sExpected: string, ydExpected: int) =
|
||||||
let
|
let
|
||||||
parsed = s.parse(f, utc())
|
parsed = s.parse(f, utc())
|
||||||
parsedStr = $parsed
|
parsedStr = $parsed
|
||||||
if parsedStr != sExpected:
|
|
||||||
echo "GOT ", parsedStr, " EXPECTED ", sExpected, " FORMAT ", f
|
|
||||||
check parsedStr == sExpected
|
check parsedStr == sExpected
|
||||||
check(parsed.yearday == ydExpected)
|
check parsed.yearday == ydExpected
|
||||||
|
|
||||||
template parseTestExcp(s, f: string) =
|
template parseTestExcp(s, f: string) =
|
||||||
expect ValueError:
|
expect ValueError:
|
||||||
|
|
@ -192,7 +113,7 @@ suite "ttimes":
|
||||||
|
|
||||||
# Generate tests for multiple timezone files where available
|
# Generate tests for multiple timezone files where available
|
||||||
# Set the TZ env var for each test
|
# Set the TZ env var for each test
|
||||||
when defined(Linux) or defined(macosx):
|
when defined(linux) or defined(macosx):
|
||||||
const tz_dir = "/usr/share/zoneinfo"
|
const tz_dir = "/usr/share/zoneinfo"
|
||||||
const f = "yyyy-MM-dd HH:mm zzz"
|
const f = "yyyy-MM-dd HH:mm zzz"
|
||||||
|
|
||||||
|
|
@ -333,7 +254,19 @@ suite "ttimes":
|
||||||
check isLeapYear(2000)
|
check isLeapYear(2000)
|
||||||
check (not isLeapYear(1900))
|
check (not isLeapYear(1900))
|
||||||
|
|
||||||
test "subtract months":
|
test "TimeInterval":
|
||||||
|
let t = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997
|
||||||
|
# Interval tests
|
||||||
|
let t2 = t - 2.years
|
||||||
|
check t2.year == 1995
|
||||||
|
let t3 = (t - 7.years - 34.minutes - 24.seconds)
|
||||||
|
check t3.year == 1990
|
||||||
|
check t3.minute == 24
|
||||||
|
check t3.second == 10
|
||||||
|
check (t + 1.hours).toTime.toUnix == t.toTime.toUnix + 60 * 60
|
||||||
|
check (t - 1.hours).toTime.toUnix == t.toTime.toUnix - 60 * 60
|
||||||
|
|
||||||
|
test "TimeInterval - months":
|
||||||
var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc())
|
var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc())
|
||||||
check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00Z"
|
check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00Z"
|
||||||
dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc())
|
dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
|
@ -405,10 +338,13 @@ suite "ttimes":
|
||||||
let tomorrow = now + day
|
let tomorrow = now + day
|
||||||
check tomorrow - now == initDuration(days = 1)
|
check tomorrow - now == initDuration(days = 1)
|
||||||
|
|
||||||
|
# Disabled for JS because it fails due to precision errors
|
||||||
|
# (The JS target uses float64 for int64).
|
||||||
|
when not defined(js):
|
||||||
test "fromWinTime/toWinTime":
|
test "fromWinTime/toWinTime":
|
||||||
check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
|
check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
|
||||||
check (-1).fromWinTime.nanosecond == convert(Seconds, Nanoseconds, 1) - 100
|
check (-1).fromWinTime.nanosecond == convert(Seconds, Nanoseconds, 1) - 100
|
||||||
check -1.fromWinTime.toWinTime == -1
|
check (-1).fromWinTime.toWinTime == -1
|
||||||
# One nanosecond is discarded due to differences in time resolution
|
# One nanosecond is discarded due to differences in time resolution
|
||||||
check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
|
check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
|
||||||
check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
|
check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
|
||||||
|
|
@ -477,6 +413,18 @@ suite "ttimes":
|
||||||
expect ValueError:
|
expect ValueError:
|
||||||
discard initTimeFormat("foo'")
|
discard initTimeFormat("foo'")
|
||||||
|
|
||||||
|
for tz in [
|
||||||
|
(staticTz(seconds = 0), "+0", "+00", "+00:00"), # UTC
|
||||||
|
(staticTz(seconds = -3600), "+1", "+01", "+01:00"), # CET
|
||||||
|
(staticTz(seconds = -39600), "+11", "+11", "+11:00"), # two digits
|
||||||
|
(staticTz(seconds = -1800), "+0", "+00", "+00:30"), # half an hour
|
||||||
|
(staticTz(seconds = 7200), "-2", "-02", "-02:00"), # positive
|
||||||
|
(staticTz(seconds = 38700), "-10", "-10", "-10:45")]: # positive with three quaters hour
|
||||||
|
let dt = initDateTime(1, mJan, 2000, 00, 00, 00, tz[0])
|
||||||
|
doAssert dt.format("z") == tz[1]
|
||||||
|
doAssert dt.format("zz") == tz[2]
|
||||||
|
doAssert dt.format("zzz") == tz[3]
|
||||||
|
|
||||||
test "parse":
|
test "parse":
|
||||||
check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z"
|
check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z"
|
||||||
parseTestExcp("+120180101", "yyyyMMdd")
|
parseTestExcp("+120180101", "yyyyMMdd")
|
||||||
|
|
@ -497,3 +445,26 @@ suite "ttimes":
|
||||||
discard parse("'", "''")
|
discard parse("'", "''")
|
||||||
|
|
||||||
parseTestExcp("2000 A", "yyyy g")
|
parseTestExcp("2000 A", "yyyy g")
|
||||||
|
|
||||||
|
test "countLeapYears":
|
||||||
|
# 1920, 2004 and 2020 are leap years, and should be counted starting at the following year
|
||||||
|
check countLeapYears(1920) + 1 == countLeapYears(1921)
|
||||||
|
check countLeapYears(2004) + 1 == countLeapYears(2005)
|
||||||
|
check countLeapYears(2020) + 1 == countLeapYears(2021)
|
||||||
|
|
||||||
|
test "timezoneConversion":
|
||||||
|
var l = now()
|
||||||
|
let u = l.utc
|
||||||
|
l = u.local
|
||||||
|
|
||||||
|
check l.timezone == local()
|
||||||
|
check u.timezone == utc()
|
||||||
|
|
||||||
|
test "getDayOfWeek":
|
||||||
|
check getDayOfWeek(01, mJan, 0000) == dSat
|
||||||
|
check getDayOfWeek(01, mJan, -0023) == dSat
|
||||||
|
check getDayOfWeek(21, mSep, 1900) == dFri
|
||||||
|
check getDayOfWeek(01, mJan, 1970) == dThu
|
||||||
|
check getDayOfWeek(21, mSep, 1970) == dMon
|
||||||
|
check getDayOfWeek(01, mJan, 2000) == dSat
|
||||||
|
check getDayOfWeek(01, mJan, 2021) == dFri
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue