better docs: times

This commit is contained in:
narimiran 2019-02-11 12:36:51 +01:00
commit 242b6eb16c

View file

@ -130,7 +130,8 @@
Duration vs TimeInterval Duration vs TimeInterval
---------------------------- ----------------------------
The ``times`` module exports two similiar types that are both used to The ``times`` module exports two similiar types that are both used to
represent some amount of time: ``Duration`` and ``TimeInterval``. represent some amount of time: `Duration <#Duration>`_ and
`TimeInterval <#TimeInterval>`_.
This section explains how they differ and when one should be prefered over the This section explains how they differ and when one should be prefered over the
other (short answer: use ``Duration`` unless support for months and years is other (short answer: use ``Duration`` unless support for months and years is
needed). needed).
@ -302,9 +303,10 @@ type
## they should never be mutated directly. Doing so is unsafe and will ## they should never be mutated directly. Doing so is unsafe and will
## result in the ``DateTime`` ending up in an invalid state. ## result in the ``DateTime`` ending up in an invalid state.
## ##
## Instead of mutating the fields directly, use the ``Duration`` ## Instead of mutating the fields directly, use the `Duration <#Duration>`_
## and ``TimeInterval`` types for arithmetic and use the ``initDateTime`` ## and `TimeInterval <#TimeInterval>`_ types for arithmetic and use the
## procedure for changing a specific field. ## `initDateTime proc <#initDateTime,MonthdayRange,Month,int,HourRange,MinuteRange,SecondRange,NanosecondRange,Timezone>`_
## for changing a specific field.
nanosecond*: NanosecondRange ## The number of nanoseconds after the second, nanosecond*: NanosecondRange ## The number of nanoseconds after the second,
## in the range 0 to 999_999_999. ## in the range 0 to 999_999_999.
second*: SecondRange ## The number of seconds after the minute, second*: SecondRange ## The number of seconds after the minute,
@ -334,7 +336,10 @@ type
## ``-3600``). ## ``-3600``).
Duration* = object ## Represents a fixed duration of time, meaning a duration Duration* = object ## Represents a fixed duration of time, meaning a duration
## that has constant length independent of the context. ## that has constant length independent of the context.
##
## To create a new ``Duration``, use `initDuration proc
## <#initDuration,int64,int64,int64,int64,int64,int64,int64,int64>`_.
seconds: int64 seconds: int64
nanosecond: NanosecondRange nanosecond: NanosecondRange
@ -348,15 +353,20 @@ type
TimeInterval* = object ## \ TimeInterval* = object ## \
## Represents a non-fixed duration of time. Can be used to add and ## Represents a non-fixed duration of time. Can be used to add and
## subtract non-fixed time units from a ``DateTime`` or ``Time``. ## subtract non-fixed time units from a `DateTime <#DateTime>`_ or
## `Time <#Time>`_.
##
## Create a new ``TimeInterval`` with `initTimeInterval proc
## <#initTimeInterval,int,int,int,int,int,int,int,int,int,int>`_.
##
## Note that ``TimeInterval`` doesn't represent a fixed duration of time, ## Note that ``TimeInterval`` doesn't represent a fixed duration of time,
## since the duration of some units depend on the context (e.g a year ## since the duration of some units depend on the context (e.g a year
## can be either 365 or 366 days long). The non-fixed time units are ## can be either 365 or 366 days long). The non-fixed time units are
## years, months, days and week. ## years, months, days and week.
## ##
## Note that ``TimeInterval``'s returned from the ``times`` module are ## Note that ``TimeInterval``'s returned from the ``times`` module are
## never normalized. If you want to normalize a time unit, ``Duration`` ## never normalized. If you want to normalize a time unit,
## should be used instead. ## `Duration <#Duration>`_ should be used instead.
nanoseconds*: int ## The number of nanoseconds nanoseconds*: int ## The number of nanoseconds
microseconds*: int ## The number of microseconds microseconds*: int ## The number of microseconds
milliseconds*: int ## The number of milliseconds milliseconds*: int ## The number of milliseconds
@ -369,7 +379,7 @@ type
years*: int ## The number of years years*: int ## The number of years
Timezone* = ref object ## \ Timezone* = ref object ## \
## Timezone interface for supporting ``DateTime``'s of arbritary ## Timezone interface for supporting `DateTime <#DateTime>`_\s of arbritary
## timezones. The ``times`` module only supplies implementations for the ## timezones. The ``times`` module only supplies implementations for the
## systems local time and UTC. ## systems local time and UTC.
zonedTimeFromTimeImpl: proc (x: Time): ZonedTime zonedTimeFromTimeImpl: proc (x: Time): ZonedTime
@ -451,7 +461,7 @@ proc nanosecond*(time: Time): NanosecondRange =
proc initDuration*(nanoseconds, microseconds, milliseconds, proc initDuration*(nanoseconds, microseconds, milliseconds,
seconds, minutes, hours, days, weeks: int64 = 0): Duration = seconds, minutes, hours, days, weeks: int64 = 0): Duration =
## Create a new duration. ## Create a new `Duration <#Duration>`_.
runnableExamples: runnableExamples:
let dur = initDuration(seconds = 1, milliseconds = 1) let dur = initDuration(seconds = 1, milliseconds = 1)
doAssert dur.milliseconds == 1 doAssert dur.milliseconds == 1
@ -473,53 +483,72 @@ proc initDuration*(nanoseconds, microseconds, milliseconds,
proc weeks*(dur: Duration): int64 {.inline.} = proc weeks*(dur: Duration): int64 {.inline.} =
## Number of whole weeks represented by the duration. ## Number of whole weeks represented by the duration.
runnableExamples:
let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4)
doAssert dur.weeks == 1
convert(Seconds, Weeks, dur.seconds) convert(Seconds, Weeks, dur.seconds)
proc days*(dur: Duration): int64 {.inline.} = proc days*(dur: Duration): int64 {.inline.} =
## Number of whole days represented by the duration. ## Number of whole days represented by the duration.
runnableExamples:
let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4)
doAssert dur.days == 9
convert(Seconds, Days, dur.seconds) convert(Seconds, Days, dur.seconds)
proc minutes*(dur: Duration): int64 {.inline.} =
## Number of whole minutes represented by the duration.
convert(Seconds, Minutes, dur.seconds)
proc hours*(dur: Duration): int64 {.inline.} = proc hours*(dur: Duration): int64 {.inline.} =
## Number of whole hours represented by the duration. ## Number of whole hours represented by the duration.
runnableExamples:
let dur = initDuration(days = 1, hours = 2, minutes = 3)
doAssert dur.hours == 26
convert(Seconds, Hours, dur.seconds) convert(Seconds, Hours, dur.seconds)
proc minutes*(dur: Duration): int64 {.inline.} =
## Number of whole minutes represented by the duration.
runnableExamples:
let dur = initDuration(days = 1, hours = 2, minutes = 3)
doAssert dur.minutes == 1563
convert(Seconds, Minutes, dur.seconds)
proc seconds*(dur: Duration): int64 {.inline.} = proc seconds*(dur: Duration): int64 {.inline.} =
## Number of whole seconds represented by the duration. ## Number of whole seconds represented by the duration.
runnableExamples:
let dur = initDuration(minutes = 10, seconds = 30)
doAssert dur.seconds == 630
dur.seconds dur.seconds
proc milliseconds*(dur: Duration): int {.inline.} = proc milliseconds*(dur: Duration): int {.inline.} =
## Number of whole milliseconds represented by the **fractional** ## Number of whole milliseconds represented by the **fractional**
## part of the duration. ## part of the duration.
runnableExamples: runnableExamples:
let dur = initDuration(seconds = 1, milliseconds = 1) let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
doAssert dur.milliseconds == 1 microseconds = 8, nanoseconds = 9)
doAssert dur.milliseconds == 7
convert(Nanoseconds, Milliseconds, dur.nanosecond) convert(Nanoseconds, Milliseconds, dur.nanosecond)
proc microseconds*(dur: Duration): int {.inline.} = proc microseconds*(dur: Duration): int {.inline.} =
## Number of whole microseconds represented by the **fractional** ## Number of whole microseconds represented by the **fractional**
## part of the duration. ## part of the duration.
runnableExamples: runnableExamples:
let dur = initDuration(seconds = 1, microseconds = 1) let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
doAssert dur.microseconds == 1 microseconds = 8, nanoseconds = 9)
doAssert dur.microseconds == 7008
convert(Nanoseconds, Microseconds, dur.nanosecond) convert(Nanoseconds, Microseconds, dur.nanosecond)
proc nanoseconds*(dur: Duration): int {.inline.} = proc nanoseconds*(dur: Duration): int {.inline.} =
## Number of whole nanoseconds represented by the **fractional** ## Number of whole nanoseconds represented by the **fractional**
## part of the duration. ## part of the duration.
runnableExamples: runnableExamples:
let dur = initDuration(seconds = 1, nanoseconds = 1) let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
doAssert dur.nanoseconds == 1 microseconds = 8, nanoseconds = 9)
doAssert dur.nanoseconds == 7008009
dur.nanosecond dur.nanosecond
proc fractional*(dur: Duration): Duration {.inline.} = proc fractional*(dur: Duration): Duration {.inline.} =
## The fractional part of duration, as a duration. ## The fractional part of duration, as a duration.
runnableExamples: runnableExamples:
let dur = initDuration(seconds = 1, nanoseconds = 5) let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
doAssert dur.fractional == initDuration(nanoseconds = 5) microseconds = 8, nanoseconds = 9)
doAssert dur.fractional == initDuration(milliseconds = 7, microseconds = 8, nanoseconds = 9)
initDuration(nanoseconds = dur.nanosecond) initDuration(nanoseconds = dur.nanosecond)
proc fromUnix*(unix: int64): Time proc fromUnix*(unix: int64): Time
@ -551,11 +580,17 @@ proc toWinTime*(t: Time): int64 =
proc isLeapYear*(year: int): bool = proc isLeapYear*(year: int): bool =
## Returns true if ``year`` is a leap year. ## Returns true if ``year`` is a leap year.
runnableExamples:
doAssert isLeapYear(2000)
doAssert not isLeapYear(1900)
year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0) year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0)
proc getDaysInMonth*(month: Month, year: int): int = proc getDaysInMonth*(month: Month, year: int): int =
## Get the number of days in ``month`` of ``year``. ## Get the number of days in ``month`` of ``year``.
# http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
runnableExamples:
doAssert getDaysInMonth(mFeb, 2000) == 29
doAssert getDaysInMonth(mFeb, 2001) == 28
case month case month
of mFeb: result = if isLeapYear(year): 29 else: 28 of mFeb: result = if isLeapYear(year): 29 else: 28
of mApr, mJun, mSep, mNov: result = 30 of mApr, mJun, mSep, mNov: result = 30
@ -563,6 +598,9 @@ proc getDaysInMonth*(month: Month, year: int): int =
proc getDaysInYear*(year: int): int = proc getDaysInYear*(year: int): int =
## Get the number of days in a ``year`` ## Get the number of days in a ``year``
runnableExamples:
doAssert getDaysInYear(2000) == 366
doAssert getDaysInYear(2001) == 365
result = 365 + (if isLeapYear(year): 1 else: 0) result = 365 + (if isLeapYear(year): 1 else: 0)
proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) proc assertValidDate(monthday: MonthdayRange, month: Month, year: int)
@ -609,6 +647,11 @@ proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int):
YeardayRange {.tags: [], raises: [], benign.} = YeardayRange {.tags: [], raises: [], benign.} =
## Returns the day of the year. ## Returns the day of the year.
## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``. ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``.
runnableExamples:
doAssert getDayOfYear(1, mJan, 2000) == 0
doAssert getDayOfYear(10, mJan, 2000) == 9
doAssert getDayOfYear(10, mFeb, 2000) == 40
assertValidDate monthday, month, year assertValidDate monthday, month, year
const daysUntilMonth: array[Month, int] = const daysUntilMonth: array[Month, int] =
[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
@ -624,6 +667,10 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay
{.tags: [], raises: [], benign.} = {.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(monthday, month, year, 0, 0, 0).weekday``. ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).weekday``.
runnableExamples:
doAssert getDayOfWeek(13, mJun, 1990) == dWed
doAssert $getDayOfWeek(13, mJun, 1990) == "Wednesday"
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
@ -670,6 +717,7 @@ proc toParts*(dur: Duration): DurationParts =
var dp = toParts(initDuration(weeks = 2, days = 1)) var dp = toParts(initDuration(weeks = 2, days = 1))
doAssert dp[Days] == 1 doAssert dp[Days] == 1
doAssert dp[Weeks] == 2 doAssert dp[Weeks] == 2
doAssert dp[Minutes] == 0
dp = toParts(initDuration(days = -1)) dp = toParts(initDuration(days = -1))
doAssert dp[Days] == -1 doAssert dp[Days] == -1
@ -766,24 +814,32 @@ proc `<`*(a, b: Duration): bool {.operator.} =
runnableExamples: runnableExamples:
doAssert initDuration(seconds = 1) < initDuration(seconds = 2) doAssert initDuration(seconds = 1) < initDuration(seconds = 2)
doAssert initDuration(seconds = -2) < initDuration(seconds = 1) doAssert initDuration(seconds = -2) < initDuration(seconds = 1)
doAssert initDuration(seconds = -2).abs < initDuration(seconds = 1).abs == false
ltImpl(a, b) ltImpl(a, b)
proc `<=`*(a, b: Duration): bool {.operator.} = proc `<=`*(a, b: Duration): bool {.operator.} =
lqImpl(a, b) lqImpl(a, b)
proc `==`*(a, b: Duration): bool {.operator.} = proc `==`*(a, b: Duration): bool {.operator.} =
runnableExamples:
let
d1 = initDuration(weeks = 1)
d2 = initDuration(days = 7)
doAssert d1 == d2
eqImpl(a, b) eqImpl(a, b)
proc `*`*(a: int64, b: Duration): Duration {.operator.} = proc `*`*(a: int64, b: Duration): Duration {.operator.} =
## Multiply a duration by some scalar. ## Multiply a duration by some scalar.
runnableExamples: runnableExamples:
doAssert 5 * initDuration(seconds = 1) == initDuration(seconds = 5) doAssert 5 * initDuration(seconds = 1) == initDuration(seconds = 5)
doAssert 3 * initDuration(minutes = 45) == initDuration(hours = 2, minutes = 15)
normalize[Duration](a * b.seconds, a * b.nanosecond) normalize[Duration](a * b.seconds, a * b.nanosecond)
proc `*`*(a: Duration, b: int64): Duration {.operator.} = proc `*`*(a: Duration, b: int64): Duration {.operator.} =
## Multiply a duration by some scalar. ## Multiply a duration by some scalar.
runnableExamples: runnableExamples:
doAssert initDuration(seconds = 1) * 5 == initDuration(seconds = 5) doAssert initDuration(seconds = 1) * 5 == initDuration(seconds = 5)
doAssert initDuration(minutes = 45) * 3 == initDuration(hours = 2, minutes = 15)
b * a b * a
proc `div`*(a: Duration, b: int64): Duration {.operator.} = proc `div`*(a: Duration, b: int64): Duration {.operator.} =
@ -791,18 +847,23 @@ proc `div`*(a: Duration, b: int64): Duration {.operator.} =
runnableExamples: runnableExamples:
doAssert initDuration(seconds = 3) div 2 == doAssert initDuration(seconds = 3) div 2 ==
initDuration(milliseconds = 1500) initDuration(milliseconds = 1500)
doAssert initDuration(minutes = 45) div 30 ==
initDuration(minutes = 1, seconds = 30)
doAssert initDuration(nanoseconds = 3) div 2 == doAssert initDuration(nanoseconds = 3) div 2 ==
initDuration(nanoseconds = 1) initDuration(nanoseconds = 1)
let carryOver = convert(Seconds, Nanoseconds, a.seconds mod b) let carryOver = convert(Seconds, Nanoseconds, a.seconds mod b)
normalize[Duration](a.seconds div b, (a.nanosecond + carryOver) div b) normalize[Duration](a.seconds div b, (a.nanosecond + carryOver) div b)
proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = proc initTime*(unix: int64, nanosecond: NanosecondRange): Time =
## Create a ``Time`` from a unix timestamp and a nanosecond part. ## Create a `Time <#Time>`_ from a unix timestamp and a nanosecond part.
result.seconds = unix result.seconds = unix
result.nanosecond = nanosecond result.nanosecond = nanosecond
proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} =
## Computes the duration between two points in time. ## Computes the duration between two points in time.
runnableExamples:
doAssert initTime(1000, 100) - initTime(500, 20) ==
initDuration(minutes = 8, seconds = 20, nanoseconds = 80)
subImpl[Duration](a, b) subImpl[Duration](a, b)
proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} = proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} =
@ -819,6 +880,8 @@ proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} =
proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} = proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} =
## Returns true iff ``a < b``, that is iff a happened before b. ## Returns true iff ``a < b``, that is iff a happened before b.
runnableExamples:
doAssert initTime(50, 0) < initTime(99, 0)
ltImpl(a, b) ltImpl(a, b)
proc `<=`*(a, b: Time): bool {.operator, extern: "ntLeTime".} = proc `<=`*(a, b: Time): bool {.operator, extern: "ntLeTime".} =
@ -1134,7 +1197,7 @@ proc now*(): DateTime {.tags: [TimeEffect], benign.} =
proc initTimeInterval*(nanoseconds, microseconds, milliseconds, proc initTimeInterval*(nanoseconds, microseconds, milliseconds,
seconds, minutes, hours, seconds, minutes, hours,
days, weeks, months, years: int = 0): TimeInterval = days, weeks, months, years: int = 0): TimeInterval =
## Creates a new ``TimeInterval``. ## Creates a new `TimeInterval <#TimeInterval>`_.
## ##
## This proc doesn't perform any normalization! For example, ## This proc doesn't perform any normalization! For example,
## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are ## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are
@ -1342,7 +1405,7 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
hour: HourRange, minute: MinuteRange, second: SecondRange, hour: HourRange, minute: MinuteRange, second: SecondRange,
nanosecond: NanosecondRange, nanosecond: NanosecondRange,
zone: Timezone = local()): DateTime = zone: Timezone = local()): DateTime =
## Create a new ``DateTime`` in the specified timezone. ## Create a new `DateTime <#DateTime>`_ in the specified timezone.
runnableExamples: runnableExamples:
let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc()) let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc())
doAssert $dt1 == "2017-03-30T00:00:00Z" doAssert $dt1 == "2017-03-30T00:00:00Z"
@ -1362,7 +1425,7 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
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,
zone: Timezone = local()): DateTime = zone: Timezone = local()): DateTime =
## Create a new ``DateTime`` in the specified timezone. ## Create a new `DateTime <#DateTime>`_ in the specified timezone.
runnableExamples: runnableExamples:
let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
doAssert $dt1 == "2017-03-30T00:00:00Z" doAssert $dt1 == "2017-03-30T00:00:00Z"
@ -1663,7 +1726,10 @@ type
Lit Lit
TimeFormat* = object ## Represents a format for parsing and printing TimeFormat* = object ## Represents a format for parsing and printing
## time types. ## time types.
##
## To create a new ``TimeFormat`` use `initTimeFormat proc
## <#initTimeFormat,string>`_.
patterns: seq[byte] ## \ patterns: seq[byte] ## \
## Contains the patterns encoded as bytes. ## Contains the patterns encoded as bytes.
## Literal values are encoded in a special way. ## Literal values are encoded in a special way.