mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Sub second time resolution (#6978)
* Add deprecation warnings to recently deprecated procs * Fix bad usage of the times module * Introduce sub second resolution * Fix usage of C's time() * Switch to nanosecond resolution * Make Time & Duration opaque again and fix some errors * Change back to TimeInterval for shorthands * Fix JS test * Fix build error for windows * Undeprecate epochTime * Documentation and minor changes * Lots of bugfixes and doc comments * Attempt to make travis & appveyor green * Fix edge cases for dealing with the local timezone * Workaround JS backend overflow/underflow bug * Use better workaround for not knowing the size of time_t * Use all available timezones for tests * Fix indentation * Add procs for accessing the fractional part of a duration * Order time units from smallest to largest since it makes more sense * Include months and years in `TimeUnit` * Review fix
This commit is contained in:
committed by
Andreas Rumpf
parent
19a1cc914f
commit
f6df2d9956
@@ -77,8 +77,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
cbos copyDir:
|
||||
os.copyDir(getString(a, 0), getString(a, 1))
|
||||
cbos getLastModificationTime:
|
||||
# depends on Time's implementation!
|
||||
setResult(a, int64(getLastModificationTime(getString(a, 0))))
|
||||
setResult(a, getLastModificationTime(getString(a, 0)).toUnix)
|
||||
cbos findExe:
|
||||
setResult(a, os.findExe(getString(a, 0)))
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ proc genOid*(): Oid =
|
||||
proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
|
||||
proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>", nodecl.}
|
||||
|
||||
var t = getTime().int32
|
||||
var t = getTime().toUnix.int32
|
||||
|
||||
var i = int32(atomicInc(incr))
|
||||
|
||||
|
||||
@@ -225,10 +225,10 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
|
||||
## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s
|
||||
## modification time is later than `b`'s.
|
||||
when defined(posix):
|
||||
result = getLastModificationTime(a) - getLastModificationTime(b) >= 0
|
||||
result = getLastModificationTime(a) - getLastModificationTime(b) >= DurationZero
|
||||
# Posix's resolution sucks so, we use '>=' for posix.
|
||||
else:
|
||||
result = getLastModificationTime(a) - getLastModificationTime(b) > 0
|
||||
result = getLastModificationTime(a) - getLastModificationTime(b) > DurationZero
|
||||
|
||||
proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
|
||||
## Returns the `current working directory`:idx:.
|
||||
|
||||
@@ -191,8 +191,8 @@ when not defined(nimscript):
|
||||
proc randomize*() {.benign.} =
|
||||
## Initializes the random number generator with a "random"
|
||||
## number, i.e. a tickcount. Note: Does not work for NimScript.
|
||||
let time = int64(times.epochTime() * 1_000_000_000)
|
||||
randomize(time)
|
||||
let now = times.getTime()
|
||||
randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanoseconds)
|
||||
|
||||
{.pop.}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,14 +17,14 @@ block localTime:
|
||||
|
||||
let a = fromUnix(1_000_000_000)
|
||||
let b = fromUnix(1_500_000_000)
|
||||
doAssert b - a == 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 staticZoneInfoFromUtc(time: Time): ZonedTime =
|
||||
result.utcOffset = -7200
|
||||
result.isDst = false
|
||||
result.adjTime = (time.toUnix + 7200).Time
|
||||
result.adjTime = time + 7200.seconds
|
||||
|
||||
proc staticZoneInfoFromTz(adjTime: Time): ZonedTIme =
|
||||
result.utcOffset = -7200
|
||||
@@ -40,5 +40,4 @@ block timezoneTests:
|
||||
doAssert $dt.utc.inZone(utcPlus2) == $dt
|
||||
|
||||
doAssert $initDateTime(01, mJan, 1911, 12, 00, 00, utc()) == "1911-01-01T12:00:00+00:00"
|
||||
# See #6752
|
||||
# doAssert $initDateTime(01, mJan, 1900, 12, 00, 00, utc()) == "0023-01-01T12:00:00+00:00"
|
||||
doAssert $initDateTime(01, mJan, 0023, 12, 00, 00, utc()) == "0023-01-01T12:00:00+00:00"
|
||||
@@ -37,8 +37,8 @@ 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 - initInterval(years = 2)).checkFormat("yyyy", "1995")
|
||||
(t4 - initInterval(years = 7, minutes = 34, seconds = 24)).checkFormat("yyyy mm ss", "1990 24 10")
|
||||
(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
|
||||
@@ -56,32 +56,34 @@ doAssert toUnix(toTime(t4L)) + t4L.utcOffset == toUnix(toTime(t4))
|
||||
|
||||
# adding intervals
|
||||
var
|
||||
a1L = toUnix(toTime(t4L + initInterval(hours = 1))) + t4L.utcOffset
|
||||
a1L = toUnix(toTime(t4L + initTimeInterval(hours = 1))) + t4L.utcOffset
|
||||
a1G = toUnix(toTime(t4)) + 60 * 60
|
||||
doAssert a1L == a1G
|
||||
|
||||
# subtracting intervals
|
||||
a1L = toUnix(toTime(t4L - initInterval(hours = 1))) + t4L.utcOffset
|
||||
a1L = toUnix(toTime(t4L - initTimeInterval(hours = 1))) + t4L.utcOffset
|
||||
a1G = toUnix(toTime(t4)) - (60 * 60)
|
||||
doAssert a1L == a1G
|
||||
|
||||
# add/subtract TimeIntervals and Time/TimeInfo
|
||||
doAssert getTime() - 1.seconds == getTime() - 3.seconds + 2.seconds
|
||||
doAssert getTime() + 65.seconds == getTime() + 1.minutes + 5.seconds
|
||||
doAssert getTime() + 60.minutes == getTime() + 1.hours
|
||||
doAssert getTime() + 24.hours == getTime() + 1.days
|
||||
doAssert getTime() + 13.months == getTime() + 1.years + 1.months
|
||||
var
|
||||
ti1 = getTime() + 1.years
|
||||
ti1 -= 1.years
|
||||
doAssert ti1 == getTime()
|
||||
ti1 += 1.days
|
||||
doAssert ti1 == getTime() + 1.days
|
||||
let now = getTime().utc
|
||||
doAssert now + convert(Seconds, Nanoseconds, 1).nanoseconds == now + 1.seconds
|
||||
doAssert now + 1.weeks == now + 7.days
|
||||
doAssert now - 1.seconds == now - 3.seconds + 2.seconds
|
||||
doAssert now + 65.seconds == now + 1.minutes + 5.seconds
|
||||
doAssert now + 60.minutes == now + 1.hours
|
||||
doAssert now + 24.hours == now + 1.days
|
||||
doAssert now + 13.months == now + 1.years + 1.months
|
||||
var ti1 = now + 1.years
|
||||
ti1 = ti1 - 1.years
|
||||
doAssert ti1 == now
|
||||
ti1 = ti1 + 1.days
|
||||
doAssert ti1 == now + 1.days
|
||||
|
||||
# Bug with adding a day to a Time
|
||||
let day = 24.hours
|
||||
let tomorrow = getTime() + day
|
||||
doAssert tomorrow - getTime() == 60*60*24
|
||||
let tomorrow = now + day
|
||||
doAssert tomorrow - now == initDuration(days = 1)
|
||||
|
||||
# Comparison between Time objects should be detected by compiler
|
||||
# as 'noSideEffect'.
|
||||
@@ -207,8 +209,8 @@ template runTimezoneTests() =
|
||||
let
|
||||
parsedJan = parse("2016-01-05 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz")
|
||||
parsedJul = parse("2016-07-01 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz")
|
||||
doAssert toTime(parsedJan) == fromUnix(1451962800)
|
||||
doAssert toTime(parsedJul) == fromUnix(1467342000)
|
||||
doAssert toTime(parsedJan).toUnix == 1451962800
|
||||
doAssert toTime(parsedJul).toUnix == 1467342000
|
||||
|
||||
suite "ttimes":
|
||||
|
||||
@@ -220,7 +222,7 @@ suite "ttimes":
|
||||
|
||||
let orig_tz = getEnv("TZ")
|
||||
var tz_cnt = 0
|
||||
for tz_fn in walkFiles(tz_dir & "/*"):
|
||||
for tz_fn in walkFiles(tz_dir & "/**/*"):
|
||||
if symlinkExists(tz_fn) or tz_fn.endsWith(".tab") or
|
||||
tz_fn.endsWith(".list"):
|
||||
continue
|
||||
@@ -252,19 +254,20 @@ suite "ttimes":
|
||||
var local = fromUnix(1469275200).local
|
||||
var utc = fromUnix(1469275200).utc
|
||||
|
||||
let claimedOffset = local.utcOffset
|
||||
let claimedOffset = initDuration(seconds = local.utcOffset)
|
||||
local.utcOffset = 0
|
||||
check claimedOffset == utc.toTime - local.toTime
|
||||
|
||||
test "issue #5704":
|
||||
putEnv("TZ", "Asia/Seoul")
|
||||
let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime - parse("19000101-000000", "yyyyMMdd-hhmmss").toTime
|
||||
check diff == 2208986872
|
||||
check diff == initDuration(seconds = 2208986872)
|
||||
|
||||
test "issue #6465":
|
||||
putEnv("TZ", "Europe/Stockholm")
|
||||
let dt = parse("2017-03-25 12:00", "yyyy-MM-dd hh:mm")
|
||||
check $(dt + 1.days) == "2017-03-26T12:00:00+02:00"
|
||||
check $(dt + initTimeInterval(days = 1)) == "2017-03-26T12:00:00+02:00"
|
||||
check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00"
|
||||
|
||||
test "datetime before epoch":
|
||||
check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52+00:00"
|
||||
@@ -362,12 +365,40 @@ suite "ttimes":
|
||||
|
||||
test "subtract months":
|
||||
var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc())
|
||||
check $(dt - 1.months) == "2017-01-01T00:00:00+00:00"
|
||||
check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00+00:00"
|
||||
dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc())
|
||||
check $(dt - 1.months) == "2017-02-15T00:00:00+00:00"
|
||||
check $(dt - initTimeInterval(months = 1)) == "2017-02-15T00:00:00+00:00"
|
||||
dt = initDateTime(31, mMar, 2017, 00, 00, 00, utc())
|
||||
# This happens due to monthday overflow. It's consistent with Phobos.
|
||||
check $(dt - 1.months) == "2017-03-03T00:00:00+00:00"
|
||||
check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00+00:00"
|
||||
|
||||
test "duration":
|
||||
let d = initDuration
|
||||
check d(hours = 48) + d(days = 5) == d(weeks = 1)
|
||||
let dt = initDateTime(01, mFeb, 2000, 00, 00, 00, 0, utc()) + d(milliseconds = 1)
|
||||
check dt.nanosecond == convert(Milliseconds, Nanoseconds, 1)
|
||||
check d(seconds = 1, milliseconds = 500) * 2 == d(seconds = 3)
|
||||
check d(seconds = 3) div 2 == d(seconds = 1, milliseconds = 500)
|
||||
check d(milliseconds = 1001).seconds == 1
|
||||
check d(seconds = 1, milliseconds = 500) - d(milliseconds = 1250) ==
|
||||
d(milliseconds = 250)
|
||||
check d(seconds = 1, milliseconds = 1) < d(seconds = 1, milliseconds = 2)
|
||||
check d(seconds = 1) <= d(seconds = 1)
|
||||
check d(seconds = 0) - d(milliseconds = 1500) == d(milliseconds = -1500)
|
||||
check d(milliseconds = -1500) == d(seconds = -1, milliseconds = -500)
|
||||
check d(seconds = -1, milliseconds = 500) == d(milliseconds = -500)
|
||||
|
||||
test "large/small dates":
|
||||
discard initDateTime(1, mJan, -35_000, 12, 00, 00, utc())
|
||||
# with local tz
|
||||
discard initDateTime(1, mJan, -35_000, 12, 00, 00)
|
||||
discard initDateTime(1, mJan, 35_000, 12, 00, 00)
|
||||
# with duration/timeinterval
|
||||
let dt = initDateTime(1, mJan, 35_000, 12, 00, 00, utc()) +
|
||||
initDuration(seconds = 1)
|
||||
check dt.second == 1
|
||||
let dt2 = dt + 35_001.years
|
||||
check $dt2 == "0001-01-01T12:00:01+00:00"
|
||||
|
||||
test "compare datetimes":
|
||||
var dt1 = now()
|
||||
|
||||
Reference in New Issue
Block a user