times.Timezone changes (#8527)
* Use floorDiv in times.nim * New implementation of times.Timezone * Tweak doc comments * Fix typo
This commit is contained in:
parent
b77d910e4e
commit
33ed8f7e73
4 changed files with 153 additions and 91 deletions
|
|
@ -40,6 +40,10 @@
|
||||||
- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
|
- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
|
||||||
to ``times.Duration`` in order to support higher time resolutions.
|
to ``times.Duration`` in order to support higher time resolutions.
|
||||||
The proc is no longer deprecated.
|
The proc is no longer deprecated.
|
||||||
|
|
||||||
|
- The ``times.Timezone`` is now an immutable ref-type that must be initialized
|
||||||
|
with an explicit constructor (``newTimezone``).
|
||||||
|
|
||||||
- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``.
|
- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``.
|
||||||
|
|
||||||
- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers
|
- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers
|
||||||
|
|
|
||||||
|
|
@ -276,20 +276,22 @@ type
|
||||||
FixedTimeUnit* = range[Nanoseconds..Weeks] ## Subrange of ``TimeUnit`` that only includes units of fixed duration.
|
FixedTimeUnit* = range[Nanoseconds..Weeks] ## Subrange of ``TimeUnit`` that only includes units of fixed duration.
|
||||||
## These are the units that can be represented by a ``Duration``.
|
## These are the units that can be represented by a ``Duration``.
|
||||||
|
|
||||||
Timezone* = object ## Timezone interface for supporting ``DateTime``'s of arbritary timezones.
|
Timezone* = ref object ## \
|
||||||
## The ``times`` module only supplies implementations for the systems local time and UTC.
|
## Timezone interface for supporting ``DateTime``'s of arbritary
|
||||||
## The members ``zoneInfoFromUtc`` and ``zoneInfoFromTz`` should not be accessed directly
|
## timezones. The ``times`` module only supplies implementations for the
|
||||||
## and are only exported so that ``Timezone`` can be implemented by other modules.
|
## systems local time and UTC.
|
||||||
zoneInfoFromUtc*: proc (time: Time): ZonedTime {.tags: [], raises: [], benign.}
|
zonedTimeFromTimeImpl: proc (x: Time): ZonedTime
|
||||||
zoneInfoFromTz*: proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.}
|
{.tags: [], raises: [], benign.}
|
||||||
name*: string ## The name of the timezone, f.ex 'Europe/Stockholm' or 'Etc/UTC'. Used for checking equality.
|
zonedTimeFromAdjTimeImpl: proc (x: Time): ZonedTime
|
||||||
## Se also: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
{.tags: [], raises: [], benign.}
|
||||||
|
name: string
|
||||||
|
|
||||||
ZonedTime* = object ## Represents a zoned instant in time that is not associated with any calendar.
|
ZonedTime* = object ## Represents a point in time with an associated
|
||||||
## This type is only used for implementing timezones.
|
## UTC offset and DST flag. This type is only used for
|
||||||
adjTime*: Time ## Time adjusted to a timezone.
|
## implementing timezones.
|
||||||
utcOffset*: int ## Offset from UTC in seconds.
|
time*: Time ## The point in time being represented.
|
||||||
## The point in time represented by ``ZonedTime`` is ``adjTime + utcOffset.seconds``.
|
utcOffset*: int ## The offset in seconds west of UTC,
|
||||||
|
## including any offset due to DST.
|
||||||
isDst*: bool ## Determines whether DST is in effect.
|
isDst*: bool ## Determines whether DST is in effect.
|
||||||
|
|
||||||
DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts
|
DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts
|
||||||
|
|
@ -343,10 +345,9 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T =
|
||||||
result.nanosecond = nanosecond.int
|
result.nanosecond = nanosecond.int
|
||||||
|
|
||||||
# Forward declarations
|
# Forward declarations
|
||||||
proc utcZoneInfoFromUtc(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
proc utcTzInfo(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
proc utcZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
proc localZonedTimeFromTime(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
proc localZoneInfoFromUtc(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
proc localZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
|
||||||
proc initTime*(unix: int64, nanosecond: NanosecondRange): Time
|
proc initTime*(unix: int64, nanosecond: NanosecondRange): Time
|
||||||
{.tags: [], raises: [], benign noSideEffect.}
|
{.tags: [], raises: [], benign noSideEffect.}
|
||||||
|
|
||||||
|
|
@ -493,7 +494,7 @@ proc fromEpochDay(epochday: int64): tuple[monthday: MonthdayRange, month: Month,
|
||||||
|
|
||||||
proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): YeardayRange {.tags: [], raises: [], benign .} =
|
proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): YeardayRange {.tags: [], raises: [], benign .} =
|
||||||
## Returns the day of the year.
|
## Returns the day of the year.
|
||||||
## Equivalent with ``initDateTime(day, month, year).yearday``.
|
## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``.
|
||||||
assertValidDate monthday, month, year
|
assertValidDate monthday, month, year
|
||||||
const daysUntilMonth: array[Month, int] = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
const daysUntilMonth: array[Month, int] = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
||||||
const daysUntilMonthLeap: array[Month, int] = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
|
const daysUntilMonthLeap: array[Month, int] = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
|
||||||
|
|
@ -505,11 +506,11 @@ proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): YeardayRan
|
||||||
|
|
||||||
proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.tags: [], raises: [], benign .} =
|
proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.tags: [], raises: [], benign .} =
|
||||||
## Returns the day of the week enum from day, month and year.
|
## Returns the day of the week enum from day, month and year.
|
||||||
## Equivalent with ``initDateTime(day, month, year).weekday``.
|
## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).weekday``.
|
||||||
assertValidDate monthday, month, year
|
assertValidDate monthday, month, year
|
||||||
# 1970-01-01 is a Thursday, we adjust to the previous Monday
|
# 1970-01-01 is a Thursday, we adjust to the previous Monday
|
||||||
let days = toEpochday(monthday, month, year) - 3
|
let days = toEpochday(monthday, month, year) - 3
|
||||||
let weeks = (if days >= 0: days else: days - 6) div 7
|
let weeks = floorDiv(days, 7)
|
||||||
let wd = days - weeks * 7
|
let wd = days - weeks * 7
|
||||||
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
|
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
|
||||||
# so we must correct for the WeekDay type.
|
# so we must correct for the WeekDay type.
|
||||||
|
|
@ -759,15 +760,14 @@ proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} =
|
||||||
seconds.inc dt.hour * secondsInHour
|
seconds.inc dt.hour * secondsInHour
|
||||||
seconds.inc dt.minute * 60
|
seconds.inc dt.minute * 60
|
||||||
seconds.inc dt.second
|
seconds.inc dt.second
|
||||||
# The code above ignores the UTC offset of `timeInfo`,
|
|
||||||
# so we need to compensate for that here.
|
|
||||||
seconds.inc dt.utcOffset
|
seconds.inc dt.utcOffset
|
||||||
result = initTime(seconds, dt.nanosecond)
|
result = initTime(seconds, dt.nanosecond)
|
||||||
|
|
||||||
proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
|
proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
|
||||||
## Create a new ``DateTime`` using ``ZonedTime`` in the specified timezone.
|
## Create a new ``DateTime`` using ``ZonedTime`` in the specified timezone.
|
||||||
let s = zt.adjTime.seconds
|
let adjTime = zt.time - initDuration(seconds = zt.utcOffset)
|
||||||
let epochday = (if s >= 0: s else: s - (secondsInDay - 1)) div secondsInDay
|
let s = adjTime.seconds
|
||||||
|
let epochday = floorDiv(s, secondsInDay)
|
||||||
var rem = s - epochday * secondsInDay
|
var rem = s - epochday * secondsInDay
|
||||||
let hour = rem div secondsInHour
|
let hour = rem div secondsInHour
|
||||||
rem = rem - hour * secondsInHour
|
rem = rem - hour * secondsInHour
|
||||||
|
|
@ -784,7 +784,7 @@ proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
|
||||||
hour: hour,
|
hour: hour,
|
||||||
minute: minute,
|
minute: minute,
|
||||||
second: second,
|
second: second,
|
||||||
nanosecond: zt.adjTime.nanosecond,
|
nanosecond: zt.time.nanosecond,
|
||||||
weekday: getDayOfWeek(d, m, y),
|
weekday: getDayOfWeek(d, m, y),
|
||||||
yearday: getDayOfYear(d, m, y),
|
yearday: getDayOfYear(d, m, y),
|
||||||
isDst: zt.isDst,
|
isDst: zt.isDst,
|
||||||
|
|
@ -792,14 +792,55 @@ proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
|
||||||
utcOffset: zt.utcOffset
|
utcOffset: zt.utcOffset
|
||||||
)
|
)
|
||||||
|
|
||||||
proc inZone*(time: Time, zone: Timezone): DateTime {.tags: [], raises: [], benign.} =
|
proc newTimezone*(
|
||||||
## Break down ``time`` into a ``DateTime`` using ``zone`` as the timezone.
|
name: string,
|
||||||
let zoneInfo = zone.zoneInfoFromUtc(time)
|
zonedTimeFromTimeImpl: proc (time: Time): ZonedTime {.tags: [], raises: [], benign.},
|
||||||
result = initDateTime(zoneInfo, zone)
|
zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.}
|
||||||
|
): Timezone =
|
||||||
|
## Create a new ``Timezone``.
|
||||||
|
##
|
||||||
|
## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used
|
||||||
|
## as the underlying implementations for ``zonedTimeFromTime`` and
|
||||||
|
## ``zonedTimeFromAdjTime``.
|
||||||
|
##
|
||||||
|
## If possible, the name parameter should match the name used in the
|
||||||
|
## tz database. If the timezone doesn't exist in the tz database, or if the
|
||||||
|
## timezone name is unknown, then any string that describes the timezone
|
||||||
|
## unambiguously can be used. Note that the timezones name is used for
|
||||||
|
## checking equality!
|
||||||
|
runnableExamples:
|
||||||
|
proc utcTzInfo(time: Time): ZonedTime =
|
||||||
|
ZonedTime(utcOffset: 0, isDst: false, time: time)
|
||||||
|
let utc = newTimezone("Etc/UTC", utcTzInfo, utcTzInfo)
|
||||||
|
Timezone(
|
||||||
|
name: name,
|
||||||
|
zonedTimeFromTimeImpl: zonedTimeFromTimeImpl,
|
||||||
|
zonedTimeFromAdjTimeImpl: zonedTimeFromAdjTimeImpl
|
||||||
|
)
|
||||||
|
|
||||||
proc inZone*(dt: DateTime, zone: Timezone): DateTime {.tags: [], raises: [], benign.} =
|
proc name*(zone: Timezone): string =
|
||||||
## Convert ``dt`` into a ``DateTime`` using ``zone`` as the timezone.
|
## The name of the timezone.
|
||||||
dt.toTime.inZone(zone)
|
##
|
||||||
|
## If possible, the name will be the name used in the tz database.
|
||||||
|
## If the timezone doesn't exist in the tz database, or if the timezone
|
||||||
|
## name is unknown, then any string that describes the timezone
|
||||||
|
## unambiguously might be used. For example, the string "LOCAL" is used
|
||||||
|
## for the systems local timezone.
|
||||||
|
##
|
||||||
|
## See also: https://en.wikipedia.org/wiki/Tz_database
|
||||||
|
zone.name
|
||||||
|
|
||||||
|
proc zonedTimeFromTime*(zone: Timezone, time: Time): ZonedTime =
|
||||||
|
## Returns the ``ZonedTime`` for some point in time.
|
||||||
|
zone.zonedTimeFromTimeImpl(time)
|
||||||
|
|
||||||
|
proc zonedTimeFromAdjTime*(zone: TimeZone, adjTime: Time): ZonedTime =
|
||||||
|
## Returns the ``ZonedTime`` for some local time.
|
||||||
|
##
|
||||||
|
## Note that the ``Time`` argument does not represent a point in time, it
|
||||||
|
## represent a local time! E.g if ``adjTime`` is ``fromUnix(0)``, it should be
|
||||||
|
## interpreted as 1970-01-01T00:00:00 in the ``zone`` timezone, not in UTC.
|
||||||
|
zone.zonedTimeFromAdjTimeImpl(adjTime)
|
||||||
|
|
||||||
proc `$`*(zone: Timezone): string =
|
proc `$`*(zone: Timezone): string =
|
||||||
## Returns the name of the timezone.
|
## Returns the name of the timezone.
|
||||||
|
|
@ -807,8 +848,20 @@ proc `$`*(zone: Timezone): string =
|
||||||
|
|
||||||
proc `==`*(zone1, zone2: Timezone): bool =
|
proc `==`*(zone1, zone2: Timezone): bool =
|
||||||
## Two ``Timezone``'s are considered equal if their name is equal.
|
## Two ``Timezone``'s are considered equal if their name is equal.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert local() == local()
|
||||||
|
doAssert local() != utc()
|
||||||
zone1.name == zone2.name
|
zone1.name == zone2.name
|
||||||
|
|
||||||
|
proc inZone*(time: Time, zone: Timezone): DateTime {.tags: [], raises: [], benign.} =
|
||||||
|
## Convert ``time`` into a ``DateTime`` using ``zone`` as the timezone.
|
||||||
|
result = initDateTime(zone.zonedTimeFromTime(time), zone)
|
||||||
|
|
||||||
|
proc inZone*(dt: DateTime, zone: Timezone): DateTime {.tags: [], raises: [], benign.} =
|
||||||
|
## Returns a ``DateTime`` representing the same point in time as ``dt`` but
|
||||||
|
## using ``zone`` as the timezone.
|
||||||
|
dt.toTime.inZone(zone)
|
||||||
|
|
||||||
proc toAdjTime(dt: DateTime): Time =
|
proc toAdjTime(dt: DateTime): Time =
|
||||||
let epochDay = toEpochday(dt.monthday, dt.month, dt.year)
|
let epochDay = toEpochday(dt.monthday, dt.month, dt.year)
|
||||||
var seconds = epochDay * secondsInDay
|
var seconds = epochDay * secondsInDay
|
||||||
|
|
@ -843,14 +896,14 @@ when defined(JS):
|
||||||
proc getYear(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
|
proc getYear(js: JsDate): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
proc setFullYear(js: JsDate, year: int): void {.tags: [], raises: [], benign, importcpp.}
|
proc setFullYear(js: JsDate, year: int): void {.tags: [], raises: [], benign, importcpp.}
|
||||||
|
|
||||||
proc localZoneInfoFromUtc(time: Time): ZonedTime =
|
proc localZonedTimeFromTime(time: Time): ZonedTime =
|
||||||
let jsDate = newDate(time.seconds.float * 1000)
|
let jsDate = newDate(time.seconds.float * 1000)
|
||||||
let offset = jsDate.getTimezoneOffset() * secondsInMin
|
let offset = jsDate.getTimezoneOffset() * secondsInMin
|
||||||
result.adjTime = time - initDuration(seconds = offset)
|
result.time = time
|
||||||
result.utcOffset = offset
|
result.utcOffset = offset
|
||||||
result.isDst = false
|
result.isDst = false
|
||||||
|
|
||||||
proc localZoneInfoFromTz(adjTime: Time): ZonedTime =
|
proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime =
|
||||||
let utcDate = newDate(adjTime.seconds.float * 1000)
|
let utcDate = newDate(adjTime.seconds.float * 1000)
|
||||||
let localDate = newDate(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(),
|
let localDate = newDate(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(),
|
||||||
utcDate.getUTCHours(), utcDate.getUTCMinutes(), utcDate.getUTCSeconds(), 0)
|
utcDate.getUTCHours(), utcDate.getUTCMinutes(), utcDate.getUTCSeconds(), 0)
|
||||||
|
|
@ -861,8 +914,8 @@ when defined(JS):
|
||||||
if utcDate.getUTCFullYear() in 0 .. 99:
|
if utcDate.getUTCFullYear() in 0 .. 99:
|
||||||
localDate.setFullYear(utcDate.getUTCFullYear())
|
localDate.setFullYear(utcDate.getUTCFullYear())
|
||||||
|
|
||||||
result.adjTime = adjTime
|
|
||||||
result.utcOffset = localDate.getTimezoneOffset() * secondsInMin
|
result.utcOffset = localDate.getTimezoneOffset() * secondsInMin
|
||||||
|
result.time = adjTime + initDuration(seconds = result.utcOffset)
|
||||||
result.isDst = false
|
result.isDst = false
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
@ -915,13 +968,13 @@ else:
|
||||||
return ((unix - tm.toAdjUnix).int, tm.isdst > 0)
|
return ((unix - tm.toAdjUnix).int, tm.isdst > 0)
|
||||||
return (0, false)
|
return (0, false)
|
||||||
|
|
||||||
proc localZoneInfoFromUtc(time: Time): ZonedTime =
|
proc localZonedTimeFromTime(time: Time): ZonedTime =
|
||||||
let (offset, dst) = getLocalOffsetAndDst(time.seconds)
|
let (offset, dst) = getLocalOffsetAndDst(time.seconds)
|
||||||
result.adjTime = time - initDuration(seconds = offset)
|
result.time = time
|
||||||
result.utcOffset = offset
|
result.utcOffset = offset
|
||||||
result.isDst = dst
|
result.isDst = dst
|
||||||
|
|
||||||
proc localZoneInfoFromTz(adjTime: Time): ZonedTime =
|
proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime =
|
||||||
var adjUnix = adjTime.seconds
|
var adjUnix = adjTime.seconds
|
||||||
let past = adjUnix - secondsInDay
|
let past = adjUnix - secondsInDay
|
||||||
let (pastOffset, _) = getLocalOffsetAndDst(past)
|
let (pastOffset, _) = getLocalOffsetAndDst(past)
|
||||||
|
|
@ -943,31 +996,34 @@ else:
|
||||||
# as a result of offset changes (normally due to dst)
|
# as a result of offset changes (normally due to dst)
|
||||||
let utcUnix = adjTime.seconds + utcOffset
|
let utcUnix = adjTime.seconds + utcOffset
|
||||||
let (finalOffset, dst) = getLocalOffsetAndDst(utcUnix)
|
let (finalOffset, dst) = getLocalOffsetAndDst(utcUnix)
|
||||||
result.adjTime = initTime(utcUnix - finalOffset, adjTime.nanosecond)
|
result.time = initTime(utcUnix, adjTime.nanosecond)
|
||||||
result.utcOffset = finalOffset
|
result.utcOffset = finalOffset
|
||||||
result.isDst = dst
|
result.isDst = dst
|
||||||
|
|
||||||
proc utcZoneInfoFromUtc(time: Time): ZonedTime =
|
proc utcTzInfo(time: Time): ZonedTime =
|
||||||
result.adjTime = time
|
ZonedTime(utcOffset: 0, isDst: false, time: time)
|
||||||
result.utcOffset = 0
|
|
||||||
result.isDst = false
|
|
||||||
|
|
||||||
proc utcZoneInfoFromTz(adjTime: Time): ZonedTime =
|
var utcInstance {.threadvar.}: Timezone
|
||||||
utcZoneInfoFromUtc(adjTime) # adjTime == time since we are in UTC
|
var localInstance {.threadvar.}: Timezone
|
||||||
|
|
||||||
proc utc*(): TimeZone =
|
proc utc*(): TimeZone =
|
||||||
## Get the ``Timezone`` implementation for the UTC timezone.
|
## Get the ``Timezone`` implementation for the UTC timezone.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert now().utc.timezone == utc()
|
doAssert now().utc.timezone == utc()
|
||||||
doAssert utc().name == "Etc/UTC"
|
doAssert utc().name == "Etc/UTC"
|
||||||
Timezone(zoneInfoFromUtc: utcZoneInfoFromUtc, zoneInfoFromTz: utcZoneInfoFromTz, name: "Etc/UTC")
|
if utcInstance.isNil:
|
||||||
|
utcInstance = newTimezone("Etc/UTC", utcTzInfo, utcTzInfo)
|
||||||
|
result = utcInstance
|
||||||
|
|
||||||
proc local*(): TimeZone =
|
proc local*(): TimeZone =
|
||||||
## Get the ``Timezone`` implementation for the local timezone.
|
## Get the ``Timezone`` implementation for the local timezone.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert now().timezone == local()
|
doAssert now().timezone == local()
|
||||||
doAssert local().name == "LOCAL"
|
doAssert local().name == "LOCAL"
|
||||||
Timezone(zoneInfoFromUtc: localZoneInfoFromUtc, zoneInfoFromTz: localZoneInfoFromTz, name: "LOCAL")
|
if localInstance.isNil:
|
||||||
|
localInstance = newTimezone("LOCAL", localZonedTimeFromTime,
|
||||||
|
localZonedTimeFromAdjTime)
|
||||||
|
result = localInstance
|
||||||
|
|
||||||
proc utc*(dt: DateTime): DateTime =
|
proc utc*(dt: DateTime): DateTime =
|
||||||
## Shorthand for ``dt.inZone(utc())``.
|
## Shorthand for ``dt.inZone(utc())``.
|
||||||
|
|
@ -1233,7 +1289,7 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
||||||
second: second,
|
second: second,
|
||||||
nanosecond: nanosecond
|
nanosecond: nanosecond
|
||||||
)
|
)
|
||||||
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)
|
result = initDateTime(zone.zonedTimeFromAdjTime(dt.toAdjTime), zone)
|
||||||
|
|
||||||
proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
||||||
hour: HourRange, minute: MinuteRange, second: SecondRange,
|
hour: HourRange, minute: MinuteRange, second: SecondRange,
|
||||||
|
|
@ -1263,16 +1319,15 @@ proc `+`*(dt: DateTime, interval: TimeInterval): DateTime =
|
||||||
let (adjDur, absDur) = evaluateInterval(dt, interval)
|
let (adjDur, absDur) = evaluateInterval(dt, interval)
|
||||||
|
|
||||||
if adjDur != DurationZero:
|
if adjDur != DurationZero:
|
||||||
var zInfo = dt.timezone.zoneInfoFromTz(dt.toAdjTime + adjDur)
|
var zt = dt.timezone.zonedTimeFromAdjTime(dt.toAdjTime + adjDur)
|
||||||
if absDur != DurationZero:
|
if absDur != DurationZero:
|
||||||
let offsetDur = initDuration(seconds = zInfo.utcOffset)
|
zt = dt.timezone.zonedTimeFromTime(zt.time + absDur)
|
||||||
zInfo = dt.timezone.zoneInfoFromUtc(zInfo.adjTime + offsetDur + absDur)
|
result = initDateTime(zt, dt.timezone)
|
||||||
result = initDateTime(zInfo, dt.timezone)
|
|
||||||
else:
|
else:
|
||||||
result = initDateTime(zInfo, dt.timezone)
|
result = initDateTime(zt, dt.timezone)
|
||||||
else:
|
else:
|
||||||
var zInfo = dt.timezone.zoneInfoFromUtc(dt.toTime + absDur)
|
var zt = dt.timezone.zonedTimeFromTime(dt.toTime + absDur)
|
||||||
result = initDateTime(zInfo, dt.timezone)
|
result = initDateTime(zt, dt.timezone)
|
||||||
|
|
||||||
proc `-`*(dt: DateTime, interval: TimeInterval): DateTime =
|
proc `-`*(dt: DateTime, interval: TimeInterval): DateTime =
|
||||||
## Subtract ``interval`` from ``dt``. Components from ``interval`` are subtracted
|
## Subtract ``interval`` from ``dt``. Components from ``interval`` are subtracted
|
||||||
|
|
@ -1319,7 +1374,7 @@ proc `<=` * (a, b: DateTime): bool =
|
||||||
return a.toTime <= b.toTime
|
return a.toTime <= b.toTime
|
||||||
|
|
||||||
proc `==`*(a, b: DateTime): bool =
|
proc `==`*(a, b: DateTime): bool =
|
||||||
## Returns true if ``a == b``, that is if both dates represent the same point in datetime.
|
## Returns true if ``a == b``, that is if both dates represent the same point in time.
|
||||||
return a.toTime == b.toTime
|
return a.toTime == b.toTime
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2065,7 +2120,7 @@ proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat,
|
||||||
|
|
||||||
if p.utcOffset.isNone:
|
if p.utcOffset.isNone:
|
||||||
# No timezone parsed - assume timezone is `zone`
|
# No timezone parsed - assume timezone is `zone`
|
||||||
result = initDateTime(zone.zoneInfoFromTz(result.toAdjTime), zone)
|
result = initDateTime(zone.zonedTimeFromAdjTime(result.toAdjTime), zone)
|
||||||
else:
|
else:
|
||||||
# Otherwise convert to `zone`
|
# Otherwise convert to `zone`
|
||||||
result.utcOffset = p.utcOffset.get()
|
result.utcOffset = p.utcOffset.get()
|
||||||
|
|
@ -2347,7 +2402,7 @@ proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign, deprec
|
||||||
proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} =
|
proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} =
|
||||||
## Returns the time in seconds since the unix epoch.
|
## Returns the time in seconds since the unix epoch.
|
||||||
##
|
##
|
||||||
## **Deprecated since v0.18.0:** use ``fromUnix`` instead
|
## **Deprecated since v0.18.0:** use ``toUnix`` instead
|
||||||
time.seconds.float + time.nanosecond / convert(Seconds, Nanoseconds, 1)
|
time.seconds.float + time.nanosecond / convert(Seconds, Nanoseconds, 1)
|
||||||
|
|
||||||
proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
|
proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
|
||||||
|
|
@ -2390,13 +2445,14 @@ proc timeInfoToTime*(dt: DateTime): Time {.tags: [], benign, deprecated.} =
|
||||||
when defined(JS):
|
when defined(JS):
|
||||||
var start = getTime()
|
var start = getTime()
|
||||||
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} =
|
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} =
|
||||||
## get the milliseconds from the start of the program.
|
|
||||||
## **Deprecated since v0.8.10:** use ``epochTime`` or ``cpuTime`` instead.
|
|
||||||
let dur = getTime() - start
|
let dur = getTime() - start
|
||||||
result = (convert(Seconds, Milliseconds, dur.seconds) +
|
result = (convert(Seconds, Milliseconds, dur.seconds) +
|
||||||
convert(Nanoseconds, Milliseconds, dur.nanosecond)).int
|
convert(Nanoseconds, Milliseconds, dur.nanosecond)).int
|
||||||
else:
|
else:
|
||||||
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} =
|
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} =
|
||||||
|
## get the milliseconds from the start of the program.
|
||||||
|
##
|
||||||
|
## **Deprecated since v0.8.10:** use ``epochTime`` or ``cpuTime`` instead.
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
|
result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
|
||||||
else:
|
else:
|
||||||
|
|
@ -2417,7 +2473,7 @@ proc getDayOfWeek*(day, month, year: int): WeekDay {.tags: [], raises: [], beni
|
||||||
proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} =
|
proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} =
|
||||||
## Returns the day of the week enum from day, month and year,
|
## Returns the day of the week enum from day, month and year,
|
||||||
## according to the Julian calendar.
|
## according to the Julian calendar.
|
||||||
## **Deprecated since v0.18.0:**
|
## **Deprecated since v0.18.0**
|
||||||
# Day & month start from one.
|
# Day & month start from one.
|
||||||
let
|
let
|
||||||
a = (14 - month) div 12
|
a = (14 - month) div 12
|
||||||
|
|
@ -2425,3 +2481,23 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} =
|
||||||
m = month + (12*a) - 2
|
m = month + (12*a) - 2
|
||||||
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
|
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
|
||||||
result = d.WeekDay
|
result = d.WeekDay
|
||||||
|
|
||||||
|
proc adjTime*(zt: ZonedTime): Time
|
||||||
|
{.deprecated: "Use zt.time instead".} =
|
||||||
|
## **Deprecated since v0.19.0:** use the ``time`` field instead.
|
||||||
|
zt.time - initDuration(seconds = zt.utcOffset)
|
||||||
|
|
||||||
|
proc `adjTime=`*(zt: var ZonedTime, adjTime: Time)
|
||||||
|
{.deprecated: "Use zt.time instead".} =
|
||||||
|
## **Deprecated since v0.19.0:** use the ``time`` field instead.
|
||||||
|
zt.time = adjTime + initDuration(seconds = zt.utcOffset)
|
||||||
|
|
||||||
|
proc zoneInfoFromUtc*(zone: Timezone, time: Time): ZonedTime
|
||||||
|
{.deprecated: "Use zonedTimeFromTime instead".} =
|
||||||
|
## **Deprecated since v0.19.0:** use ``zonedTimeFromTime`` instead.
|
||||||
|
zone.zonedTimeFromTime(time)
|
||||||
|
|
||||||
|
proc zoneInfoFromTz*(zone: Timezone, adjTime: Time): ZonedTime
|
||||||
|
{.deprecated: "Use zonedTimeFromAdjTime instead".} =
|
||||||
|
## **Deprecated since v0.19.0:** use the ``zonedTimeFromAdjTime`` instead.
|
||||||
|
zone.zonedTimeFromAdjTime(adjTime)
|
||||||
|
|
@ -21,17 +21,17 @@ 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.
|
# Because we can't change the timezone JS uses, we define a simple static timezone for testing.
|
||||||
|
|
||||||
proc staticZoneInfoFromUtc(time: Time): ZonedTime =
|
proc zonedTimeFromTime(time: Time): ZonedTime =
|
||||||
result.utcOffset = -7200
|
result.utcOffset = -7200
|
||||||
result.isDst = false
|
result.isDst = false
|
||||||
result.adjTime = time + 7200.seconds
|
result.time = time
|
||||||
|
|
||||||
proc staticZoneInfoFromTz(adjTime: Time): ZonedTIme =
|
proc zonedTimeFromAdjTime(adjTime: Time): ZonedTIme =
|
||||||
result.utcOffset = -7200
|
result.utcOffset = -7200
|
||||||
result.isDst = false
|
result.isDst = false
|
||||||
result.adjTime = adjTime
|
result.time = adjTime + initDuration(seconds = -7200)
|
||||||
|
|
||||||
let utcPlus2 = Timezone(zoneInfoFromUtc: staticZoneInfoFromUtc, zoneInfoFromTz: staticZoneInfoFromTz, name: "")
|
let utcPlus2 = newTimezone("", zonedTimeFromTime, zonedTimeFromAdjTime)
|
||||||
|
|
||||||
block timezoneTests:
|
block timezoneTests:
|
||||||
let dt = initDateTime(01, mJan, 2017, 12, 00, 00, utcPlus2)
|
let dt = initDateTime(01, mJan, 2017, 12, 00, 00, utcPlus2)
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,17 @@ import
|
||||||
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
|
||||||
|
|
||||||
proc zoneInfoFromTz(adjTime: Time): ZonedTime {.locks: 0.} =
|
proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime {.locks: 0.} =
|
||||||
result.isDst = false
|
result.isDst = false
|
||||||
result.utcOffset = offset
|
result.utcOffset = offset
|
||||||
result.adjTime = adjTime
|
result.time = adjTime + initDuration(seconds = offset)
|
||||||
|
|
||||||
proc zoneInfoFromUtc(time: Time): ZonedTime {.locks: 0.}=
|
proc zonedTimeFromTime(time: Time): ZonedTime {.locks: 0.}=
|
||||||
result.isDst = false
|
result.isDst = false
|
||||||
result.utcOffset = offset
|
result.utcOffset = offset
|
||||||
result.adjTime = fromUnix(time.toUnix - offset)
|
result.time = time
|
||||||
|
|
||||||
result.name = ""
|
|
||||||
result.zoneInfoFromTz = zoneInfoFromTz
|
|
||||||
result.zoneInfoFromUtc = zoneInfoFromUtc
|
|
||||||
|
|
||||||
|
newTimezone("", zonedTimeFromTime, zonedTImeFromAdjTime)
|
||||||
|
|
||||||
# $ date --date='@2147483647'
|
# $ date --date='@2147483647'
|
||||||
# Tue 19 Jan 03:14:07 GMT 2038
|
# Tue 19 Jan 03:14:07 GMT 2038
|
||||||
|
|
@ -322,22 +319,7 @@ suite "ttimes":
|
||||||
parseTestExcp("-1 BC", "UUUU g")
|
parseTestExcp("-1 BC", "UUUU g")
|
||||||
|
|
||||||
test "dynamic timezone":
|
test "dynamic timezone":
|
||||||
proc staticOffset(offset: int): Timezone =
|
let tz = staticTz(seconds = -9000)
|
||||||
proc zoneInfoFromTz(adjTime: Time): ZonedTime =
|
|
||||||
result.isDst = false
|
|
||||||
result.utcOffset = offset
|
|
||||||
result.adjTime = adjTime
|
|
||||||
|
|
||||||
proc zoneInfoFromUtc(time: Time): ZonedTime =
|
|
||||||
result.isDst = false
|
|
||||||
result.utcOffset = offset
|
|
||||||
result.adjTime = fromUnix(time.toUnix - offset)
|
|
||||||
|
|
||||||
result.name = ""
|
|
||||||
result.zoneInfoFromTz = zoneInfoFromTz
|
|
||||||
result.zoneInfoFromUtc = zoneInfoFromUtc
|
|
||||||
|
|
||||||
let tz = staticOffset(-9000)
|
|
||||||
let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz)
|
let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz)
|
||||||
check dt.utcOffset == -9000
|
check dt.utcOffset == -9000
|
||||||
check dt.isDst == false
|
check dt.isDst == false
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue