fixed merge conflict
This commit is contained in:
commit
12996c08a1
30 changed files with 879 additions and 332 deletions
14
changelog.md
14
changelog.md
|
|
@ -39,6 +39,9 @@
|
||||||
The proc is no longer deprecated.
|
The proc is no longer deprecated.
|
||||||
- ``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
|
||||||
|
(previously it used floor division like Python). Use ``math.floorMod`` for the old behavior.
|
||||||
|
|
||||||
#### Breaking changes in the compiler
|
#### Breaking changes in the compiler
|
||||||
|
|
||||||
- The undocumented ``#? braces`` parsing mode was removed.
|
- The undocumented ``#? braces`` parsing mode was removed.
|
||||||
|
|
@ -57,6 +60,11 @@
|
||||||
- Added the proc ``times.convert`` for converting between different time units,
|
- Added the proc ``times.convert`` for converting between different time units,
|
||||||
e.g days to seconds.
|
e.g days to seconds.
|
||||||
- Added the proc ``algorithm.binarySearch[T, K]`` with the ```cmp``` parameter.
|
- Added the proc ``algorithm.binarySearch[T, K]`` with the ```cmp``` parameter.
|
||||||
|
- Added the proc ``algorithm.upperBound``.
|
||||||
|
- Added inverse hyperbolic functions, ``math.arcsinh``, ``math.arccosh`` and ``math.arctanh`` procs.
|
||||||
|
- Added cotangent, secant and cosecant procs ``math.cot``, ``math.sec`` and ``math.csc``; and their hyperbolic, inverse and inverse hyperbolic functions, ``math.coth``, ``math.sech``, ``math.csch``, ``math.arccot``, ``math.arcsec``, ``math.arccsc``, ``math.arccoth``, ``math.arcsech`` and ``math.arccsch`` procs.
|
||||||
|
- Added the procs ``math.floorMod`` and ``math.floorDiv`` for floor based integer division.
|
||||||
|
- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals.
|
||||||
|
|
||||||
### Library changes
|
### Library changes
|
||||||
|
|
||||||
|
|
@ -76,8 +84,8 @@
|
||||||
- The `terminal` module now exports additional procs for generating ANSI color
|
- The `terminal` module now exports additional procs for generating ANSI color
|
||||||
codes as strings.
|
codes as strings.
|
||||||
- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc.
|
- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc.
|
||||||
- An exception raised from ``test`` block of ``unittest`` now show its type in
|
- An exception raised from a ``test`` block of ``unittest`` now shows its type in
|
||||||
error message
|
error message.
|
||||||
- The ``compiler/nimeval`` API was rewritten to simplify the "compiler as an
|
- The ``compiler/nimeval`` API was rewritten to simplify the "compiler as an
|
||||||
API". Using the Nim compiler and its VM as a scripting engine has never been
|
API". Using the Nim compiler and its VM as a scripting engine has never been
|
||||||
easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to
|
easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to
|
||||||
|
|
@ -87,7 +95,7 @@
|
||||||
### Language additions
|
### Language additions
|
||||||
|
|
||||||
- Dot calls combined with explicit generic instantiations can now be written
|
- Dot calls combined with explicit generic instantiations can now be written
|
||||||
as ``x.y[:z]``. ``x.y[:z]`` that is transformed into ``y[z](x)`` in the parser.
|
as ``x.y[:z]`` which is transformed into ``y[z](x)`` by the parser.
|
||||||
- ``func`` is now an alias for ``proc {.noSideEffect.}``.
|
- ``func`` is now an alias for ``proc {.noSideEffect.}``.
|
||||||
- In order to make ``for`` loops and iterators more flexible to use Nim now
|
- In order to make ``for`` loops and iterators more flexible to use Nim now
|
||||||
supports so called "for-loop macros". See
|
supports so called "for-loop macros". See
|
||||||
|
|
|
||||||
|
|
@ -1100,7 +1100,7 @@ proc getSomeInitName(m: PSym, suffix: string): Rope =
|
||||||
if {sfSystemModule, sfMainModule} * m.flags == {}:
|
if {sfSystemModule, sfMainModule} * m.flags == {}:
|
||||||
result = m.owner.name.s.mangle.rope
|
result = m.owner.name.s.mangle.rope
|
||||||
result.add "_"
|
result.add "_"
|
||||||
result.add m.name.s
|
result.add m.name.s.mangle
|
||||||
result.add suffix
|
result.add suffix
|
||||||
|
|
||||||
proc getInitName(m: PSym): Rope =
|
proc getInitName(m: PSym): Rope =
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ proc commonType*(x, y: PType): PType =
|
||||||
a = a.lastSon.skipTypes({tyGenericInst})
|
a = a.lastSon.skipTypes({tyGenericInst})
|
||||||
b = b.lastSon.skipTypes({tyGenericInst})
|
b = b.lastSon.skipTypes({tyGenericInst})
|
||||||
if a.kind == tyObject and b.kind == tyObject:
|
if a.kind == tyObject and b.kind == tyObject:
|
||||||
result = commonSuperclass(a, b)
|
result = commonSuperclass(a, b, k)
|
||||||
# this will trigger an error later:
|
# this will trigger an error later:
|
||||||
if result.isNil or result == a: return x
|
if result.isNil or result == a: return x
|
||||||
if result == b: return y
|
if result == b: return y
|
||||||
|
|
|
||||||
|
|
@ -1044,7 +1044,7 @@ proc inheritanceDiff*(a, b: PType): int =
|
||||||
inc(result)
|
inc(result)
|
||||||
result = high(int)
|
result = high(int)
|
||||||
|
|
||||||
proc commonSuperclass*(a, b: PType): PType =
|
proc commonSuperclass*(a, b: PType, k: TTypeKind): PType =
|
||||||
# quick check: are they the same?
|
# quick check: are they the same?
|
||||||
if sameObjectTypes(a, b): return a
|
if sameObjectTypes(a, b): return a
|
||||||
|
|
||||||
|
|
@ -1060,8 +1060,12 @@ proc commonSuperclass*(a, b: PType): PType =
|
||||||
x = x.sons[0]
|
x = x.sons[0]
|
||||||
var y = b
|
var y = b
|
||||||
while y != nil:
|
while y != nil:
|
||||||
|
var t = y # bug #7818, save type before skip
|
||||||
y = skipTypes(y, skipPtrs)
|
y = skipTypes(y, skipPtrs)
|
||||||
if ancestors.contains(y.id): return y
|
if ancestors.contains(y.id):
|
||||||
|
# bug #7818, defer the previous skipTypes
|
||||||
|
if k in {tyRef, tyPtr}: t = y
|
||||||
|
return t
|
||||||
y = y.sons[0]
|
y = y.sons[0]
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
=====================================================
|
=====================================================
|
||||||
Nim -- a Compiler for Nim. https://nim-lang.org/
|
Nim -- a Compiler for Nim. https://nim-lang.org/
|
||||||
|
|
||||||
Copyright (C) 2006-2017 Andreas Rumpf. All rights reserved.
|
Copyright (C) 2006-2018 Andreas Rumpf. All rights reserved.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
||||||
|
|
@ -3196,7 +3196,7 @@ notation. (Thus an operator can have more than two parameters):
|
||||||
# Multiply and add
|
# Multiply and add
|
||||||
result = a * b + c
|
result = a * b + c
|
||||||
|
|
||||||
assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
|
assert `*+`(3, 4, 6) == `+`(`*`(a, b), c)
|
||||||
|
|
||||||
|
|
||||||
Export marker
|
Export marker
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
|
||||||
var a = 0
|
var a = 0
|
||||||
for c in items(string(formatstr)):
|
for c in items(string(formatstr)):
|
||||||
if c == '?':
|
if c == '?':
|
||||||
if args[a] == nil:
|
if args[a].isNil:
|
||||||
add(result, "NULL")
|
add(result, "NULL")
|
||||||
else:
|
else:
|
||||||
add(result, dbQuote(args[a]))
|
add(result, dbQuote(args[a]))
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## import db_sqlite
|
## import db_sqlite
|
||||||
## let db = open("localhost", "user", "password", "dbname")
|
## let db = open("mytest.db", nil, nil, nil) # user, password, database name can be nil
|
||||||
## db.close()
|
## db.close()
|
||||||
##
|
##
|
||||||
## Creating a table
|
## Creating a table
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
##
|
##
|
||||||
## import db_sqlite, math
|
## import db_sqlite, math
|
||||||
##
|
##
|
||||||
## let theDb = open("mytest.db", nil, nil, nil)
|
## let theDb = open("mytest.db", "", "", "")
|
||||||
##
|
##
|
||||||
## theDb.exec(sql"Drop table if exists myTestTbl")
|
## theDb.exec(sql"Drop table if exists myTestTbl")
|
||||||
## theDb.exec(sql("""create table myTestTbl (
|
## theDb.exec(sql("""create table myTestTbl (
|
||||||
|
|
|
||||||
|
|
@ -122,14 +122,14 @@ const
|
||||||
onlySafeCode = true
|
onlySafeCode = true
|
||||||
|
|
||||||
proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.closure.}): int =
|
proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.closure.}): int =
|
||||||
## same as binarySearch except that if key is not in `a` then this
|
## Returns a position to the first element in the `a` that is greater than `key`, or last
|
||||||
## returns the location where `key` would be if it were. In other
|
## if no such element is found. In other words if you have a sorted sequence and you call
|
||||||
## words if you have a sorted sequence and you call
|
|
||||||
## insert(thing, elm, lowerBound(thing, elm))
|
## insert(thing, elm, lowerBound(thing, elm))
|
||||||
## the sequence will still be sorted.
|
## the sequence will still be sorted.
|
||||||
##
|
##
|
||||||
## `cmp` is the comparator function to use, the expected return values are
|
## The first version uses `cmp` to compare the elements. The expected return values are
|
||||||
## the same as that of system.cmp.
|
## the same as that of system.cmp.
|
||||||
|
## The second version uses the default comparison function `cmp`.
|
||||||
##
|
##
|
||||||
## example::
|
## example::
|
||||||
##
|
##
|
||||||
|
|
@ -150,6 +150,36 @@ proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.clo
|
||||||
|
|
||||||
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
||||||
|
|
||||||
|
proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.closure.}): int =
|
||||||
|
## Returns a position to the first element in the `a` that is not less
|
||||||
|
## (i.e. greater or equal to) than `key`, or last if no such element is found.
|
||||||
|
## In other words if you have a sorted sequence and you call
|
||||||
|
## insert(thing, elm, upperBound(thing, elm))
|
||||||
|
## the sequence will still be sorted.
|
||||||
|
##
|
||||||
|
## The first version uses `cmp` to compare the elements. The expected return values are
|
||||||
|
## the same as that of system.cmp.
|
||||||
|
## The second version uses the default comparison function `cmp`.
|
||||||
|
##
|
||||||
|
## example::
|
||||||
|
##
|
||||||
|
## var arr = @[1,2,3,4,6,7,8,9]
|
||||||
|
## arr.insert(5, arr.upperBound(4))
|
||||||
|
## # after running the above arr is `[1,2,3,4,5,6,7,8,9]`
|
||||||
|
result = a.low
|
||||||
|
var count = a.high - a.low + 1
|
||||||
|
var step, pos: int
|
||||||
|
while count != 0:
|
||||||
|
step = count shr 1
|
||||||
|
pos = result + step
|
||||||
|
if cmp(a[pos], key) <= 0:
|
||||||
|
result = pos + 1
|
||||||
|
count -= step + 1
|
||||||
|
else:
|
||||||
|
count = step
|
||||||
|
|
||||||
|
proc upperBound*[T](a: openArray[T], key: T): int = upperBound(a, key, cmp[T])
|
||||||
|
|
||||||
template `<-` (a, b) =
|
template `<-` (a, b) =
|
||||||
when false:
|
when false:
|
||||||
a = b
|
a = b
|
||||||
|
|
@ -546,6 +576,11 @@ when isMainModule:
|
||||||
doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 4
|
doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 4
|
||||||
doAssert lowerBound([1,2,3,10], 11) == 4
|
doAssert lowerBound([1,2,3,10], 11) == 4
|
||||||
|
|
||||||
|
block upperBound:
|
||||||
|
doAssert upperBound([1,2,4], 3, system.cmp[int]) == 2
|
||||||
|
doAssert upperBound([1,2,2,3], 3, system.cmp[int]) == 4
|
||||||
|
doAssert upperBound([1,2,3,5], 3) == 3
|
||||||
|
|
||||||
block fillEmptySeq:
|
block fillEmptySeq:
|
||||||
var s = newSeq[int]()
|
var s = newSeq[int]()
|
||||||
s.fill(0)
|
s.fill(0)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ type
|
||||||
Complex* = tuple[re, im: float]
|
Complex* = tuple[re, im: float]
|
||||||
## a complex number, consisting of a real and an imaginary part
|
## a complex number, consisting of a real and an imaginary part
|
||||||
|
|
||||||
|
const
|
||||||
|
im*: Complex = (re: 0.0, im: 1.0)
|
||||||
|
## The imaginary unit. √-1.
|
||||||
|
|
||||||
proc toComplex*(x: SomeInteger): Complex =
|
proc toComplex*(x: SomeInteger): Complex =
|
||||||
## Convert some integer ``x`` to a complex number.
|
## Convert some integer ``x`` to a complex number.
|
||||||
result.re = x
|
result.re = x
|
||||||
|
|
|
||||||
|
|
@ -558,6 +558,8 @@ proc escapeJson*(s: string; result: var string) =
|
||||||
of '\t': result.add("\\t")
|
of '\t': result.add("\\t")
|
||||||
of '\r': result.add("\\r")
|
of '\r': result.add("\\r")
|
||||||
of '"': result.add("\\\"")
|
of '"': result.add("\\\"")
|
||||||
|
of '\0'..'\7': result.add("\\u000" & $ord(c))
|
||||||
|
of '\14'..'\31': result.add("\\u00" & $ord(c))
|
||||||
of '\\': result.add("\\\\")
|
of '\\': result.add("\\\\")
|
||||||
else: result.add(c)
|
else: result.add(c)
|
||||||
result.add("\"")
|
result.add("\"")
|
||||||
|
|
@ -1581,6 +1583,7 @@ when isMainModule:
|
||||||
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
||||||
|
|
||||||
doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
|
doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
|
||||||
|
doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0020\"" # for #7887
|
||||||
|
|
||||||
# Test with extra data
|
# Test with extra data
|
||||||
when not defined(js):
|
when not defined(js):
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
|
||||||
for i in items(x): result = result + i
|
for i in items(x): result = result + i
|
||||||
|
|
||||||
{.push noSideEffect.}
|
{.push noSideEffect.}
|
||||||
when not defined(JS):
|
when not defined(JS): # C
|
||||||
proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
|
proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
|
||||||
proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".}
|
proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".}
|
||||||
## Computes the square root of `x`.
|
## Computes the square root of `x`.
|
||||||
|
|
@ -144,12 +144,33 @@ when not defined(JS):
|
||||||
proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".}
|
proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".}
|
||||||
proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
|
proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
|
||||||
## Computes the common logarithm (base 10) of `x`
|
## Computes the common logarithm (base 10) of `x`
|
||||||
proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0)
|
proc log2*(x: float32): float32 {.importc: "log2f", header: "<math.h>".}
|
||||||
|
proc log2*(x: float64): float64 {.importc: "log2", header: "<math.h>".}
|
||||||
## Computes the binary logarithm (base 2) of `x`
|
## Computes the binary logarithm (base 2) of `x`
|
||||||
proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
|
proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
|
||||||
proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
|
proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
|
||||||
## Computes the exponential function of `x` (pow(E, x))
|
## Computes the exponential function of `x` (pow(E, x))
|
||||||
|
|
||||||
|
proc sin*(x: float32): float32 {.importc: "sinf", header: "<math.h>".}
|
||||||
|
proc sin*(x: float64): float64 {.importc: "sin", header: "<math.h>".}
|
||||||
|
## Computes the sine of `x`
|
||||||
|
proc cos*(x: float32): float32 {.importc: "cosf", header: "<math.h>".}
|
||||||
|
proc cos*(x: float64): float64 {.importc: "cos", header: "<math.h>".}
|
||||||
|
## Computes the cosine of `x`
|
||||||
|
proc tan*(x: float32): float32 {.importc: "tanf", header: "<math.h>".}
|
||||||
|
proc tan*(x: float64): float64 {.importc: "tan", header: "<math.h>".}
|
||||||
|
## Computes the tangent of `x`
|
||||||
|
|
||||||
|
proc sinh*(x: float32): float32 {.importc: "sinhf", header: "<math.h>".}
|
||||||
|
proc sinh*(x: float64): float64 {.importc: "sinh", header: "<math.h>".}
|
||||||
|
## Computes the hyperbolic sine of `x`
|
||||||
|
proc cosh*(x: float32): float32 {.importc: "coshf", header: "<math.h>".}
|
||||||
|
proc cosh*(x: float64): float64 {.importc: "cosh", header: "<math.h>".}
|
||||||
|
## Computes the hyperbolic cosine of `x`
|
||||||
|
proc tanh*(x: float32): float32 {.importc: "tanhf", header: "<math.h>".}
|
||||||
|
proc tanh*(x: float64): float64 {.importc: "tanh", header: "<math.h>".}
|
||||||
|
## Computes the hyperbolic tangent of `x`
|
||||||
|
|
||||||
proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
|
proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
|
||||||
proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
|
proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
|
||||||
## Computes the arc cosine of `x`
|
## Computes the arc cosine of `x`
|
||||||
|
|
@ -166,33 +187,80 @@ when not defined(JS):
|
||||||
## results even when the resulting angle is near pi/2 or -pi/2
|
## results even when the resulting angle is near pi/2 or -pi/2
|
||||||
## (`x` near 0).
|
## (`x` near 0).
|
||||||
|
|
||||||
proc cos*(x: float32): float32 {.importc: "cosf", header: "<math.h>".}
|
proc arcsinh*(x: float32): float32 {.importc: "asinhf", header: "<math.h>".}
|
||||||
proc cos*(x: float64): float64 {.importc: "cos", header: "<math.h>".}
|
proc arcsinh*(x: float64): float64 {.importc: "asinh", header: "<math.h>".}
|
||||||
## Computes the cosine of `x`
|
## Computes the inverse hyperbolic sine of `x`
|
||||||
|
proc arccosh*(x: float32): float32 {.importc: "acoshf", header: "<math.h>".}
|
||||||
|
proc arccosh*(x: float64): float64 {.importc: "acosh", header: "<math.h>".}
|
||||||
|
## Computes the inverse hyperbolic cosine of `x`
|
||||||
|
proc arctanh*(x: float32): float32 {.importc: "atanhf", header: "<math.h>".}
|
||||||
|
proc arctanh*(x: float64): float64 {.importc: "atanh", header: "<math.h>".}
|
||||||
|
## Computes the inverse hyperbolic tangent of `x`
|
||||||
|
|
||||||
proc cosh*(x: float32): float32 {.importc: "coshf", header: "<math.h>".}
|
else: # JS
|
||||||
proc cosh*(x: float64): float64 {.importc: "cosh", header: "<math.h>".}
|
proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.}
|
||||||
## Computes the hyperbolic cosine of `x`
|
proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.}
|
||||||
|
|
||||||
|
proc ln*(x: float32): float32 {.importc: "Math.log", nodecl.}
|
||||||
|
proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.}
|
||||||
|
proc log10*(x: float32): float32 {.importc: "Math.log10", nodecl.}
|
||||||
|
proc log10*(x: float64): float64 {.importc: "Math.log10", nodecl.}
|
||||||
|
proc log2*(x: float32): float32 {.importc: "Math.log2", nodecl.}
|
||||||
|
proc log2*(x: float64): float64 {.importc: "Math.log2", nodecl.}
|
||||||
|
proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.}
|
||||||
|
proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.}
|
||||||
|
|
||||||
|
proc sin*[T: float32|float64](x: T): T {.importc: "Math.sin", nodecl.}
|
||||||
|
proc cos*[T: float32|float64](x: T): T {.importc: "Math.cos", nodecl.}
|
||||||
|
proc tan*[T: float32|float64](x: T): T {.importc: "Math.tan", nodecl.}
|
||||||
|
|
||||||
|
proc sinh*[T: float32|float64](x: T): T {.importc: "Math.sinh", nodecl.}
|
||||||
|
proc cosh*[T: float32|float64](x: T): T {.importc: "Math.cosh", nodecl.}
|
||||||
|
proc tanh*[T: float32|float64](x: T): T {.importc: "Math.tanh", nodecl.}
|
||||||
|
|
||||||
|
proc arcsin*[T: float32|float64](x: T): T {.importc: "Math.asin", nodecl.}
|
||||||
|
proc arccos*[T: float32|float64](x: T): T {.importc: "Math.acos", nodecl.}
|
||||||
|
proc arctan*[T: float32|float64](x: T): T {.importc: "Math.atan", nodecl.}
|
||||||
|
proc arctan2*[T: float32|float64](y, x: T): T {.importC: "Math.atan2", nodecl.}
|
||||||
|
|
||||||
|
proc arcsinh*[T: float32|float64](x: T): T {.importc: "Math.asinh", nodecl.}
|
||||||
|
proc arccosh*[T: float32|float64](x: T): T {.importc: "Math.acosh", nodecl.}
|
||||||
|
proc arctanh*[T: float32|float64](x: T): T {.importc: "Math.atanh", nodecl.}
|
||||||
|
|
||||||
|
proc cot*[T: float32|float64](x: T): T = 1.0 / tan(x)
|
||||||
|
## Computes the cotangent of `x`
|
||||||
|
proc sec*[T: float32|float64](x: T): T = 1.0 / cos(x)
|
||||||
|
## Computes the secant of `x`.
|
||||||
|
proc csc*[T: float32|float64](x: T): T = 1.0 / sin(x)
|
||||||
|
## Computes the cosecant of `x`
|
||||||
|
|
||||||
|
proc coth*[T: float32|float64](x: T): T = 1.0 / tanh(x)
|
||||||
|
## Computes the hyperbolic cotangent of `x`
|
||||||
|
proc sech*[T: float32|float64](x: T): T = 1.0 / cosh(x)
|
||||||
|
## Computes the hyperbolic secant of `x`
|
||||||
|
proc csch*[T: float32|float64](x: T): T = 1.0 / sinh(x)
|
||||||
|
## Computes the hyperbolic cosecant of `x`
|
||||||
|
|
||||||
|
proc arccot*[T: float32|float64](x: T): T = arctan(1.0 / x)
|
||||||
|
## Computes the inverse cotangent of `x`
|
||||||
|
proc arcsec*[T: float32|float64](x: T): T = arccos(1.0 / x)
|
||||||
|
## Computes the inverse secant of `x`
|
||||||
|
proc arccsc*[T: float32|float64](x: T): T = arcsin(1.0 / x)
|
||||||
|
## Computes the inverse cosecant of `x`
|
||||||
|
|
||||||
|
proc arccoth*[T: float32|float64](x: T): T = arctanh(1.0 / x)
|
||||||
|
## Computes the inverse hyperbolic cotangent of `x`
|
||||||
|
proc arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x)
|
||||||
|
## Computes the inverse hyperbolic secant of `x`
|
||||||
|
proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x)
|
||||||
|
## Computes the inverse hyperbolic cosecant of `x`
|
||||||
|
|
||||||
|
when not defined(JS): # C
|
||||||
proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "<math.h>".}
|
proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "<math.h>".}
|
||||||
proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".}
|
proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".}
|
||||||
## Computes the hypotenuse of a right-angle triangle with `x` and
|
## Computes the hypotenuse of a right-angle triangle with `x` and
|
||||||
## `y` as its base and height. Equivalent to ``sqrt(x*x + y*y)``.
|
## `y` as its base and height. Equivalent to ``sqrt(x*x + y*y)``.
|
||||||
|
|
||||||
proc sinh*(x: float32): float32 {.importc: "sinhf", header: "<math.h>".}
|
|
||||||
proc sinh*(x: float64): float64 {.importc: "sinh", header: "<math.h>".}
|
|
||||||
## Computes the hyperbolic sine of `x`
|
|
||||||
proc sin*(x: float32): float32 {.importc: "sinf", header: "<math.h>".}
|
|
||||||
proc sin*(x: float64): float64 {.importc: "sin", header: "<math.h>".}
|
|
||||||
## Computes the sine of `x`
|
|
||||||
|
|
||||||
proc tan*(x: float32): float32 {.importc: "tanf", header: "<math.h>".}
|
|
||||||
proc tan*(x: float64): float64 {.importc: "tan", header: "<math.h>".}
|
|
||||||
## Computes the tangent of `x`
|
|
||||||
proc tanh*(x: float32): float32 {.importc: "tanhf", header: "<math.h>".}
|
|
||||||
proc tanh*(x: float64): float64 {.importc: "tanh", header: "<math.h>".}
|
|
||||||
## Computes the hyperbolic tangent of `x`
|
|
||||||
|
|
||||||
proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
|
proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
|
||||||
proc pow*(x, y: float64): float64 {.importc: "pow", header: "<math.h>".}
|
proc pow*(x, y: float64): float64 {.importc: "pow", header: "<math.h>".}
|
||||||
## computes x to power raised of y.
|
## computes x to power raised of y.
|
||||||
|
|
@ -295,57 +363,31 @@ when not defined(JS):
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## echo trunc(PI) # 3.0
|
## echo trunc(PI) # 3.0
|
||||||
|
|
||||||
proc fmod*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".}
|
proc fmod*(x, y: float32): float32 {.deprecated, importc: "fmodf", header: "<math.h>".}
|
||||||
proc fmod*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".}
|
proc fmod*(x, y: float64): float64 {.deprecated, importc: "fmod", header: "<math.h>".}
|
||||||
## Computes the remainder of `x` divided by `y`
|
## Computes the remainder of `x` divided by `y`
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## echo fmod(-2.5, 0.3) ## -0.1
|
## echo fmod(-2.5, 0.3) ## -0.1
|
||||||
|
|
||||||
else:
|
proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".}
|
||||||
proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.}
|
proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".}
|
||||||
proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.}
|
## Computes the modulo operation for float operators.
|
||||||
|
else: # JS
|
||||||
|
proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y)
|
||||||
|
proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
|
||||||
|
proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.}
|
||||||
proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.}
|
proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.}
|
||||||
proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.}
|
proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.}
|
||||||
proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.}
|
proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.}
|
||||||
proc ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.}
|
proc ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.}
|
||||||
|
|
||||||
proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.}
|
|
||||||
proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.}
|
|
||||||
proc ln*(x: float32): float32 {.importc: "Math.log", nodecl.}
|
|
||||||
proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.}
|
|
||||||
proc log10*[T: float32|float64](x: T): T = return ln(x) / ln(10.0)
|
|
||||||
proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0)
|
|
||||||
|
|
||||||
proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.}
|
|
||||||
proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.}
|
|
||||||
proc round0(x: float): float {.importc: "Math.round", nodecl.}
|
proc round0(x: float): float {.importc: "Math.round", nodecl.}
|
||||||
|
proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.}
|
||||||
|
proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.}
|
||||||
|
|
||||||
proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
|
proc `mod`*(x, y: float32): float32 {.importcpp: "# % #".}
|
||||||
proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.}
|
proc `mod`*(x, y: float64): float64 {.importcpp: "# % #".}
|
||||||
|
## Computes the modulo operation for float operators.
|
||||||
proc arccos*(x: float32): float32 {.importc: "Math.acos", nodecl.}
|
|
||||||
proc arccos*(x: float64): float64 {.importc: "Math.acos", nodecl.}
|
|
||||||
proc arcsin*(x: float32): float32 {.importc: "Math.asin", nodecl.}
|
|
||||||
proc arcsin*(x: float64): float64 {.importc: "Math.asin", nodecl.}
|
|
||||||
proc arctan*(x: float32): float32 {.importc: "Math.atan", nodecl.}
|
|
||||||
proc arctan*(x: float64): float64 {.importc: "Math.atan", nodecl.}
|
|
||||||
proc arctan2*(y, x: float32): float32 {.importC: "Math.atan2", nodecl.}
|
|
||||||
proc arctan2*(y, x: float64): float64 {.importc: "Math.atan2", nodecl.}
|
|
||||||
|
|
||||||
proc cos*(x: float32): float32 {.importc: "Math.cos", nodecl.}
|
|
||||||
proc cos*(x: float64): float64 {.importc: "Math.cos", nodecl.}
|
|
||||||
proc cosh*(x: float32): float32 = return (exp(x)+exp(-x))*0.5
|
|
||||||
proc cosh*(x: float64): float64 = return (exp(x)+exp(-x))*0.5
|
|
||||||
proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y)
|
|
||||||
proc sinh*[T: float32|float64](x: T): T = return (exp(x)-exp(-x))*0.5
|
|
||||||
proc sin*(x: float32): float32 {.importc: "Math.sin", nodecl.}
|
|
||||||
proc sin*(x: float64): float64 {.importc: "Math.sin", nodecl.}
|
|
||||||
proc tan*(x: float32): float32 {.importc: "Math.tan", nodecl.}
|
|
||||||
proc tan*(x: float64): float64 {.importc: "Math.tan", nodecl.}
|
|
||||||
proc tanh*[T: float32|float64](x: T): T =
|
|
||||||
var y = exp(2.0*x)
|
|
||||||
return (y-1.0)/(y+1.0)
|
|
||||||
|
|
||||||
proc round*[T: float32|float64](x: T, places: int = 0): T =
|
proc round*[T: float32|float64](x: T, places: int = 0): T =
|
||||||
## Round a floating point number.
|
## Round a floating point number.
|
||||||
|
|
@ -362,6 +404,21 @@ proc round*[T: float32|float64](x: T, places: int = 0): T =
|
||||||
var mult = pow(10.0, places.T)
|
var mult = pow(10.0, places.T)
|
||||||
result = round0(x*mult)/mult
|
result = round0(x*mult)/mult
|
||||||
|
|
||||||
|
proc floorDiv*[T: SomeInteger](x, y: T): T =
|
||||||
|
## Floor division is conceptually defined as ``floor(x / y)``.
|
||||||
|
## This is different from the ``div`` operator, which is defined
|
||||||
|
## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv``
|
||||||
|
## rounds down.
|
||||||
|
result = x div y
|
||||||
|
let r = x mod y
|
||||||
|
if (r > 0 and y < 0) or (r < 0 and y > 0): result.dec 1
|
||||||
|
|
||||||
|
proc floorMod*[T: SomeNumber](x, y: T): T =
|
||||||
|
## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y).
|
||||||
|
## This proc behaves the same as the ``%`` operator in python.
|
||||||
|
result = x mod y
|
||||||
|
if (result > 0 and y < 0) or (result < 0 and y > 0): result += y
|
||||||
|
|
||||||
when not defined(JS):
|
when not defined(JS):
|
||||||
proc c_frexp*(x: float32, exponent: var int32): float32 {.
|
proc c_frexp*(x: float32, exponent: var int32): float32 {.
|
||||||
importc: "frexp", header: "<math.h>".}
|
importc: "frexp", header: "<math.h>".}
|
||||||
|
|
@ -426,15 +483,6 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
|
||||||
## `NaN`.
|
## `NaN`.
|
||||||
ord(T(0) < x) - ord(x < T(0))
|
ord(T(0) < x) - ord(x < T(0))
|
||||||
|
|
||||||
proc `mod`*[T: float32|float64](x, y: T): T =
|
|
||||||
## Computes the modulo operation for float operators. Equivalent
|
|
||||||
## to ``x - y * floor(x/y)``. Note that the remainder will always
|
|
||||||
## have the same sign as the divisor.
|
|
||||||
##
|
|
||||||
## .. code-block:: nim
|
|
||||||
## echo (4.0 mod -3.1) # -2.2
|
|
||||||
result = if y == 0.0: x else: x - y * (x/y).floor
|
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
@ -599,3 +647,19 @@ when isMainModule:
|
||||||
doAssert fac(2) == 2
|
doAssert fac(2) == 2
|
||||||
doAssert fac(3) == 6
|
doAssert fac(3) == 6
|
||||||
doAssert fac(4) == 24
|
doAssert fac(4) == 24
|
||||||
|
|
||||||
|
block: # floorMod/floorDiv
|
||||||
|
doAssert floorDiv(8, 3) == 2
|
||||||
|
doAssert floorMod(8, 3) == 2
|
||||||
|
|
||||||
|
doAssert floorDiv(8, -3) == -3
|
||||||
|
doAssert floorMod(8, -3) == -1
|
||||||
|
|
||||||
|
doAssert floorDiv(-8, 3) == -3
|
||||||
|
doAssert floorMod(-8, 3) == 1
|
||||||
|
|
||||||
|
doAssert floorDiv(-8, -3) == 2
|
||||||
|
doAssert floorMod(-8, -3) == -2
|
||||||
|
|
||||||
|
doAssert floorMod(8.0, -3.0) ==~ -1.0
|
||||||
|
doAssert floorMod(-8.5, 3.0) ==~ 0.5
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,33 @@ proc abs*[T](x: Rational[T]): Rational[T] =
|
||||||
result.num = abs x.num
|
result.num = abs x.num
|
||||||
result.den = abs x.den
|
result.den = abs x.den
|
||||||
|
|
||||||
|
proc `div`*[T: SomeInteger](x, y: Rational[T]): T =
|
||||||
|
## Computes the rational truncated division.
|
||||||
|
(x.num * y.den) div (y.num * x.den)
|
||||||
|
|
||||||
|
proc `mod`*[T: SomeInteger](x, y: Rational[T]): Rational[T] =
|
||||||
|
## Computes the rational modulo by truncated division (remainder).
|
||||||
|
## This is same as ``x - (x div y) * y``.
|
||||||
|
result = ((x.num * y.den) mod (y.num * x.den)) // (x.den * y.den)
|
||||||
|
reduce(result)
|
||||||
|
|
||||||
|
proc floorDiv*[T: SomeInteger](x, y: Rational[T]): T =
|
||||||
|
## Computes the rational floor division.
|
||||||
|
##
|
||||||
|
## Floor division is conceptually defined as ``floor(x / y)``.
|
||||||
|
## This is different from the ``div`` operator, which is defined
|
||||||
|
## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv``
|
||||||
|
## rounds down.
|
||||||
|
floorDiv(x.num * y.den, y.num * x.den)
|
||||||
|
|
||||||
|
proc floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] =
|
||||||
|
## Computes the rational modulo by floor division (modulo).
|
||||||
|
##
|
||||||
|
## This is same as ``x - floorDiv(x, y) * y``.
|
||||||
|
## This proc behaves the same as the ``%`` operator in python.
|
||||||
|
result = floorMod(x.num * y.den, y.num * x.den) // (x.den * y.den)
|
||||||
|
reduce(result)
|
||||||
|
|
||||||
proc hash*[T](x: Rational[T]): Hash =
|
proc hash*[T](x: Rational[T]): Hash =
|
||||||
## Computes hash for rational `x`
|
## Computes hash for rational `x`
|
||||||
# reduce first so that hash(x) == hash(y) for x == y
|
# reduce first so that hash(x) == hash(y) for x == y
|
||||||
|
|
@ -339,3 +366,12 @@ when isMainModule:
|
||||||
assert toRational(0.33) == 33 // 100
|
assert toRational(0.33) == 33 // 100
|
||||||
assert toRational(0.22) == 11 // 50
|
assert toRational(0.22) == 11 // 50
|
||||||
assert toRational(10.0) == 10 // 1
|
assert toRational(10.0) == 10 // 1
|
||||||
|
|
||||||
|
assert (1//1) div (3//10) == 3
|
||||||
|
assert (-1//1) div (3//10) == -3
|
||||||
|
assert (3//10) mod (1//1) == 3//10
|
||||||
|
assert (-3//10) mod (1//1) == -3//10
|
||||||
|
assert floorDiv(1//1, 3//10) == 3
|
||||||
|
assert floorDiv(-1//1, 3//10) == -4
|
||||||
|
assert floorMod(3//10, 1//1) == 3//10
|
||||||
|
assert floorMod(-3//10, 1//1) == 7//10
|
||||||
|
|
|
||||||
|
|
@ -524,8 +524,26 @@ proc format*(value: SomeFloat; specifier: string; res: var string) =
|
||||||
" of 'e', 'E', 'f', 'F', 'g', 'G' but got: " & spec.typ)
|
" of 'e', 'E', 'f', 'F', 'g', 'G' but got: " & spec.typ)
|
||||||
|
|
||||||
var f = formatBiggestFloat(value, fmode, spec.precision)
|
var f = formatBiggestFloat(value, fmode, spec.precision)
|
||||||
if value >= 0.0 and spec.sign != '-':
|
var sign = false
|
||||||
f = spec.sign & f
|
if value >= 0.0:
|
||||||
|
if spec.sign != '-':
|
||||||
|
f = spec.sign & f
|
||||||
|
sign = true
|
||||||
|
else:
|
||||||
|
sign = true
|
||||||
|
|
||||||
|
if spec.padWithZero:
|
||||||
|
var sign_str = ""
|
||||||
|
if sign:
|
||||||
|
sign_str = $f[0]
|
||||||
|
f = f[1..^1]
|
||||||
|
|
||||||
|
let toFill = spec.minimumWidth - f.len - ord(sign)
|
||||||
|
if toFill > 0:
|
||||||
|
f = repeat('0', toFill) & f
|
||||||
|
if sign:
|
||||||
|
f = sign_str & f
|
||||||
|
|
||||||
# the default for numbers is right-alignment:
|
# the default for numbers is right-alignment:
|
||||||
let align = if spec.align == '\0': '>' else: spec.align
|
let align = if spec.align == '\0': '>' else: spec.align
|
||||||
let result = alignString(f, spec.minimumWidth,
|
let result = alignString(f, spec.minimumWidth,
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,9 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
conds.add resLen
|
conds.add resLen
|
||||||
|
|
||||||
template at(s: string; i: int): char = (if i < s.len: s[i] else: '\0')
|
template at(s: string; i: int): char = (if i < s.len: s[i] else: '\0')
|
||||||
|
template matchError() =
|
||||||
|
error("type mismatch between pattern '$" & pattern[p] & "' (position: " & $p & ") and " & $getType(results[i]) &
|
||||||
|
" var '" & repr(results[i]) & "'")
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
var p = 0
|
var p = 0
|
||||||
|
|
@ -338,37 +341,37 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
if i < results.len and getType(results[i]).typeKind == ntyString:
|
if i < results.len and getType(results[i]).typeKind == ntyString:
|
||||||
matchBind "parseIdent"
|
matchBind "parseIdent"
|
||||||
else:
|
else:
|
||||||
error("no string var given for $w")
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of 'b':
|
of 'b':
|
||||||
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
||||||
matchBind "parseBin"
|
matchBind "parseBin"
|
||||||
else:
|
else:
|
||||||
error("no int var given for $b")
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of 'o':
|
of 'o':
|
||||||
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
||||||
matchBind "parseOct"
|
matchBind "parseOct"
|
||||||
else:
|
else:
|
||||||
error("no int var given for $o")
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of 'i':
|
of 'i':
|
||||||
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
||||||
matchBind "parseInt"
|
matchBind "parseInt"
|
||||||
else:
|
else:
|
||||||
error("no int var given for $i")
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of 'h':
|
of 'h':
|
||||||
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
if i < results.len and getType(results[i]).typeKind == ntyInt:
|
||||||
matchBind "parseHex"
|
matchBind "parseHex"
|
||||||
else:
|
else:
|
||||||
error("no int var given for $h")
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of 'f':
|
of 'f':
|
||||||
if i < results.len and getType(results[i]).typeKind == ntyFloat:
|
if i < results.len and getType(results[i]).typeKind == ntyFloat:
|
||||||
matchBind "parseFloat"
|
matchBind "parseFloat"
|
||||||
else:
|
else:
|
||||||
error("no float var given for $f")
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of 's':
|
of 's':
|
||||||
conds.add newCall(bindSym"inc", idx, newCall(bindSym"skipWhitespace", inp, idx))
|
conds.add newCall(bindSym"inc", idx, newCall(bindSym"skipWhitespace", inp, idx))
|
||||||
|
|
@ -392,7 +395,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
conds.add newCall(bindSym"!=", resLen, newLit min)
|
conds.add newCall(bindSym"!=", resLen, newLit min)
|
||||||
conds.add resLen
|
conds.add resLen
|
||||||
else:
|
else:
|
||||||
error("no string var given for $" & pattern[p])
|
matchError
|
||||||
inc i
|
inc i
|
||||||
of '{':
|
of '{':
|
||||||
inc p
|
inc p
|
||||||
|
|
@ -414,7 +417,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
conds.add newCall(bindSym"!=", resLen, newLit 0)
|
conds.add newCall(bindSym"!=", resLen, newLit 0)
|
||||||
conds.add resLen
|
conds.add resLen
|
||||||
else:
|
else:
|
||||||
error("no var given for $" & expr)
|
error("no var given for $" & expr & " (position: " & $p & ")")
|
||||||
inc i
|
inc i
|
||||||
of '[':
|
of '[':
|
||||||
inc p
|
inc p
|
||||||
|
|
|
||||||
|
|
@ -1854,6 +1854,10 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
|
||||||
##
|
##
|
||||||
## If ``precision == -1``, it tries to format it nicely.
|
## If ``precision == -1``, it tries to format it nicely.
|
||||||
when defined(js):
|
when defined(js):
|
||||||
|
var precision = precision
|
||||||
|
if precision == -1:
|
||||||
|
# use the same default precision as c_sprintf
|
||||||
|
precision = 6
|
||||||
var res: cstring
|
var res: cstring
|
||||||
case format
|
case format
|
||||||
of ffDefault:
|
of ffDefault:
|
||||||
|
|
@ -1863,6 +1867,9 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
|
||||||
of ffScientific:
|
of ffScientific:
|
||||||
{.emit: "`res` = `f`.toExponential(`precision`);".}
|
{.emit: "`res` = `f`.toExponential(`precision`);".}
|
||||||
result = $res
|
result = $res
|
||||||
|
if 1.0 / f == -Inf:
|
||||||
|
# JavaScript removes the "-" from negative Zero, add it back here
|
||||||
|
result = "-" & $res
|
||||||
for i in 0 ..< result.len:
|
for i in 0 ..< result.len:
|
||||||
# Depending on the locale either dot or comma is produced,
|
# Depending on the locale either dot or comma is produced,
|
||||||
# but nothing else is possible:
|
# but nothing else is possible:
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
# of the standard library!
|
# of the standard library!
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, parseutils
|
strutils, parseutils, algorithm, math
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
||||||
|
|
@ -183,6 +183,11 @@ type
|
||||||
## The point in time represented by ``ZonedTime`` is ``adjTime + utcOffset.seconds``.
|
## The point in time represented by ``ZonedTime`` is ``adjTime + utcOffset.seconds``.
|
||||||
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
|
||||||
|
TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
|
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
|
||||||
TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].}
|
TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].}
|
||||||
|
|
||||||
|
|
@ -229,31 +234,23 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T =
|
||||||
result.seconds -= 1
|
result.seconds -= 1
|
||||||
result.nanosecond = nanosecond.int
|
result.nanosecond = nanosecond.int
|
||||||
|
|
||||||
proc initTime*(unix: int64, nanosecond: NanosecondRange): Time =
|
# Forward declarations
|
||||||
## Create a ``Time`` from a unix timestamp and a nanosecond part.
|
proc utcZoneInfoFromUtc(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
result.seconds = unix
|
proc utcZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
result.nanosecond = nanosecond
|
proc localZoneInfoFromUtc(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
|
proc localZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
||||||
|
proc initTime*(unix: int64, nanosecond: NanosecondRange): Time
|
||||||
|
{.tags: [], raises: [], benign noSideEffect.}
|
||||||
|
|
||||||
|
proc initDuration*(nanoseconds, microseconds, milliseconds,
|
||||||
|
seconds, minutes, hours, days, weeks: int64 = 0): Duration
|
||||||
|
{.tags: [], raises: [], benign noSideEffect.}
|
||||||
|
|
||||||
proc nanosecond*(time: Time): NanosecondRange =
|
proc nanosecond*(time: Time): NanosecondRange =
|
||||||
## Get the fractional part of a ``Time`` as the number
|
## Get the fractional part of a ``Time`` as the number
|
||||||
## of nanoseconds of the second.
|
## of nanoseconds of the second.
|
||||||
time.nanosecond
|
time.nanosecond
|
||||||
|
|
||||||
proc initDuration*(nanoseconds, microseconds, milliseconds,
|
|
||||||
seconds, minutes, hours, days, weeks: int64 = 0): Duration =
|
|
||||||
let seconds = convert(Weeks, Seconds, weeks) +
|
|
||||||
convert(Days, Seconds, days) +
|
|
||||||
convert(Minutes, Seconds, minutes) +
|
|
||||||
convert(Hours, Seconds, hours) +
|
|
||||||
convert(Seconds, Seconds, seconds) +
|
|
||||||
convert(Milliseconds, Seconds, milliseconds) +
|
|
||||||
convert(Microseconds, Seconds, microseconds) +
|
|
||||||
convert(Nanoseconds, Seconds, nanoseconds)
|
|
||||||
let nanoseconds = (convert(Milliseconds, Nanoseconds, milliseconds mod 1000) +
|
|
||||||
convert(Microseconds, Nanoseconds, microseconds mod 1_000_000) +
|
|
||||||
nanoseconds mod 1_000_000_000).int
|
|
||||||
# Nanoseconds might be negative so we must normalize.
|
|
||||||
result = normalize[Duration](seconds, nanoseconds)
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
@ -306,63 +303,6 @@ proc fractional*(dur: Duration): Duration {.inline.} =
|
||||||
doAssert dur.fractional == initDuration(nanoseconds = 5)
|
doAssert dur.fractional == initDuration(nanoseconds = 5)
|
||||||
initDuration(nanoseconds = dur.nanosecond)
|
initDuration(nanoseconds = dur.nanosecond)
|
||||||
|
|
||||||
const DurationZero* = initDuration() ## Zero value for durations. Useful for comparisons.
|
|
||||||
##
|
|
||||||
## .. code-block:: nim
|
|
||||||
##
|
|
||||||
## doAssert initDuration(seconds = 1) > DurationZero
|
|
||||||
## doAssert initDuration(seconds = 0) == DurationZero
|
|
||||||
|
|
||||||
proc `$`*(dur: Duration): string =
|
|
||||||
## Human friendly string representation of ``dur``.
|
|
||||||
runnableExamples:
|
|
||||||
doAssert $initDuration(seconds = 2) == "2 seconds"
|
|
||||||
doAssert $initDuration(weeks = 1, days = 2) == "1 week and 2 days"
|
|
||||||
doAssert $initDuration(hours = 1, minutes = 2, seconds = 3) == "1 hour, 2 minutes, and 3 seconds"
|
|
||||||
doAssert $initDuration(milliseconds = -1500) == "-1 second and -500 milliseconds"
|
|
||||||
var parts = newSeq[string]()
|
|
||||||
var remS = dur.seconds
|
|
||||||
var remNs = dur.nanosecond.int
|
|
||||||
|
|
||||||
# Normally ``nanoseconds`` should always be positive, but
|
|
||||||
# that makes no sense when printing.
|
|
||||||
if remS < 0:
|
|
||||||
remNs -= convert(Seconds, Nanoseconds, 1)
|
|
||||||
remS.inc 1
|
|
||||||
|
|
||||||
const unitStrings: array[FixedTimeUnit, string] = [
|
|
||||||
"nanosecond", "microsecond", "millisecond", "second", "minute", "hour", "day", "week"
|
|
||||||
]
|
|
||||||
|
|
||||||
for unit in countdown(Weeks, Seconds):
|
|
||||||
let quantity = convert(Seconds, unit, remS)
|
|
||||||
remS = remS mod convert(unit, Seconds, 1)
|
|
||||||
|
|
||||||
if quantity.abs == 1:
|
|
||||||
parts.add $quantity & " " & unitStrings[unit]
|
|
||||||
elif quantity != 0:
|
|
||||||
parts.add $quantity & " " & unitStrings[unit] & "s"
|
|
||||||
|
|
||||||
for unit in countdown(Milliseconds, Nanoseconds):
|
|
||||||
let quantity = convert(Nanoseconds, unit, remNs)
|
|
||||||
remNs = remNs mod convert(unit, Nanoseconds, 1)
|
|
||||||
|
|
||||||
if quantity.abs == 1:
|
|
||||||
parts.add $quantity & " " & unitStrings[unit]
|
|
||||||
elif quantity != 0:
|
|
||||||
parts.add $quantity & " " & unitStrings[unit] & "s"
|
|
||||||
|
|
||||||
result = ""
|
|
||||||
if parts.len == 0:
|
|
||||||
result.add "0 nanoseconds"
|
|
||||||
elif parts.len == 1:
|
|
||||||
result = parts[0]
|
|
||||||
elif parts.len == 2:
|
|
||||||
result = parts[0] & " and " & parts[1]
|
|
||||||
else:
|
|
||||||
for part in parts[0..high(parts)-1]:
|
|
||||||
result.add part & ", "
|
|
||||||
result.add "and " & parts[high(parts)]
|
|
||||||
|
|
||||||
proc fromUnix*(unix: int64): Time {.benign, tags: [], raises: [], noSideEffect.} =
|
proc fromUnix*(unix: int64): Time {.benign, tags: [], raises: [], noSideEffect.} =
|
||||||
## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``) to a ``Time``.
|
## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``) to a ``Time``.
|
||||||
|
|
@ -372,6 +312,9 @@ proc fromUnix*(unix: int64): Time {.benign, tags: [], raises: [], noSideEffect.}
|
||||||
|
|
||||||
proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} =
|
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:
|
||||||
|
doAssert fromUnix(0).toUnix() == 0
|
||||||
|
|
||||||
t.seconds
|
t.seconds
|
||||||
|
|
||||||
proc fromWinTime*(win: int64): Time =
|
proc fromWinTime*(win: int64): Time =
|
||||||
|
|
@ -464,11 +407,6 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.
|
||||||
# so we must correct for the WeekDay type.
|
# so we must correct for the WeekDay type.
|
||||||
result = if wd == 0: dSun else: WeekDay(wd - 1)
|
result = if wd == 0: dSun else: WeekDay(wd - 1)
|
||||||
|
|
||||||
# Forward declarations
|
|
||||||
proc utcZoneInfoFromUtc(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
|
||||||
proc utcZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
|
||||||
proc localZoneInfoFromUtc(time: Time): ZonedTime {.tags: [], raises: [], benign .}
|
|
||||||
proc localZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benign .}
|
|
||||||
|
|
||||||
{. pragma: operator, rtl, noSideEffect, benign .}
|
{. pragma: operator, rtl, noSideEffect, benign .}
|
||||||
|
|
||||||
|
|
@ -489,6 +427,114 @@ template lqImpl(a: Duration|Time, b: Duration|Time): bool =
|
||||||
template eqImpl(a: Duration|Time, b: Duration|Time): bool =
|
template eqImpl(a: Duration|Time, b: Duration|Time): bool =
|
||||||
a.seconds == b.seconds and a.nanosecond == b.nanosecond
|
a.seconds == b.seconds and a.nanosecond == b.nanosecond
|
||||||
|
|
||||||
|
proc initDuration*(nanoseconds, microseconds, milliseconds,
|
||||||
|
seconds, minutes, hours, days, weeks: int64 = 0): Duration =
|
||||||
|
runnableExamples:
|
||||||
|
let dur = initDuration(seconds = 1, milliseconds = 1)
|
||||||
|
doAssert dur.milliseconds == 1
|
||||||
|
doAssert dur.seconds == 1
|
||||||
|
|
||||||
|
let seconds = convert(Weeks, Seconds, weeks) +
|
||||||
|
convert(Days, Seconds, days) +
|
||||||
|
convert(Minutes, Seconds, minutes) +
|
||||||
|
convert(Hours, Seconds, hours) +
|
||||||
|
convert(Seconds, Seconds, seconds) +
|
||||||
|
convert(Milliseconds, Seconds, milliseconds) +
|
||||||
|
convert(Microseconds, Seconds, microseconds) +
|
||||||
|
convert(Nanoseconds, Seconds, nanoseconds)
|
||||||
|
let nanoseconds = (convert(Milliseconds, Nanoseconds, milliseconds mod 1000) +
|
||||||
|
convert(Microseconds, Nanoseconds, microseconds mod 1_000_000) +
|
||||||
|
nanoseconds mod 1_000_000_000).int
|
||||||
|
# Nanoseconds might be negative so we must normalize.
|
||||||
|
result = normalize[Duration](seconds, nanoseconds)
|
||||||
|
|
||||||
|
const DurationZero* = initDuration() ## \
|
||||||
|
## Zero value for durations. Useful for comparisons.
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
##
|
||||||
|
## doAssert initDuration(seconds = 1) > DurationZero
|
||||||
|
## doAssert initDuration(seconds = 0) == DurationZero
|
||||||
|
|
||||||
|
proc toParts*(dur: Duration): DurationParts =
|
||||||
|
## Converts a duration into an array consisting of fixed time units.
|
||||||
|
##
|
||||||
|
## Each value in the array gives information about a specific unit of
|
||||||
|
## time, for example ``result[Days]`` gives a count of days.
|
||||||
|
##
|
||||||
|
## This procedure is useful for converting ``Duration`` values to strings.
|
||||||
|
runnableExamples:
|
||||||
|
var dp = toParts(initDuration(weeks=2, days=1))
|
||||||
|
doAssert dp[Days] == 1
|
||||||
|
doAssert dp[Weeks] == 2
|
||||||
|
dp = toParts(initDuration(days = -1))
|
||||||
|
doAssert dp[Days] == -1
|
||||||
|
|
||||||
|
var remS = dur.seconds
|
||||||
|
var remNs = dur.nanosecond.int
|
||||||
|
|
||||||
|
# Ensure the same sign for seconds and nanoseconds
|
||||||
|
if remS < 0 and remNs != 0:
|
||||||
|
remNs -= convert(Seconds, Nanoseconds, 1)
|
||||||
|
remS.inc 1
|
||||||
|
|
||||||
|
for unit in countdown(Weeks, Seconds):
|
||||||
|
let quantity = convert(Seconds, unit, remS)
|
||||||
|
remS = remS mod convert(unit, Seconds, 1)
|
||||||
|
|
||||||
|
result[unit] = quantity
|
||||||
|
|
||||||
|
for unit in countdown(Milliseconds, Nanoseconds):
|
||||||
|
let quantity = convert(Nanoseconds, unit, remNs)
|
||||||
|
remNs = remNs mod convert(unit, Nanoseconds, 1)
|
||||||
|
|
||||||
|
result[unit] = quantity
|
||||||
|
|
||||||
|
proc stringifyUnit*(value: int | int64, unit: string): string =
|
||||||
|
## Stringify time unit with it's name, lowercased
|
||||||
|
runnableExamples:
|
||||||
|
doAssert stringifyUnit(2, "Seconds") == "2 seconds"
|
||||||
|
doAssert stringifyUnit(1, "Years") == "1 year"
|
||||||
|
result = ""
|
||||||
|
result.add($value)
|
||||||
|
result.add(" ")
|
||||||
|
if abs(value) != 1:
|
||||||
|
result.add(unit.toLowerAscii())
|
||||||
|
else:
|
||||||
|
result.add(unit[0..^2].toLowerAscii())
|
||||||
|
|
||||||
|
proc humanizeParts(parts: seq[string]): string =
|
||||||
|
## Make date string parts human-readable
|
||||||
|
|
||||||
|
result = ""
|
||||||
|
if parts.len == 0:
|
||||||
|
result.add "0 nanoseconds"
|
||||||
|
elif parts.len == 1:
|
||||||
|
result = parts[0]
|
||||||
|
elif parts.len == 2:
|
||||||
|
result = parts[0] & " and " & parts[1]
|
||||||
|
else:
|
||||||
|
for part in parts[0..high(parts)-1]:
|
||||||
|
result.add part & ", "
|
||||||
|
result.add "and " & parts[high(parts)]
|
||||||
|
|
||||||
|
proc `$`*(dur: Duration): string =
|
||||||
|
## Human friendly string representation of ``Duration``.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert $initDuration(seconds = 2) == "2 seconds"
|
||||||
|
doAssert $initDuration(weeks = 1, days = 2) == "1 week and 2 days"
|
||||||
|
doAssert $initDuration(hours = 1, minutes = 2, seconds = 3) == "1 hour, 2 minutes, and 3 seconds"
|
||||||
|
doAssert $initDuration(milliseconds = -1500) == "-1 second and -500 milliseconds"
|
||||||
|
var parts = newSeq[string]()
|
||||||
|
var numParts = toParts(dur)
|
||||||
|
|
||||||
|
for unit in countdown(Weeks, Nanoseconds):
|
||||||
|
let quantity = numParts[unit]
|
||||||
|
if quantity != 0.int64:
|
||||||
|
parts.add(stringifyUnit(quantity, $unit))
|
||||||
|
|
||||||
|
result = humanizeParts(parts)
|
||||||
|
|
||||||
proc `+`*(a, b: Duration): Duration {.operator.} =
|
proc `+`*(a, b: Duration): Duration {.operator.} =
|
||||||
## Add two durations together.
|
## Add two durations together.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -535,7 +581,7 @@ proc `*`*(a: int64, b: Duration): Duration {.operator} =
|
||||||
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 5 * initDuration(seconds = 1) == initDuration(seconds = 5)
|
doAssert initDuration(seconds = 1) * 5 == initDuration(seconds = 5)
|
||||||
b * a
|
b * a
|
||||||
|
|
||||||
proc `div`*(a: Duration, b: int64): Duration {.operator} =
|
proc `div`*(a: Duration, b: int64): Duration {.operator} =
|
||||||
|
|
@ -546,6 +592,11 @@ proc `div`*(a: Duration, b: int64): Duration {.operator} =
|
||||||
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 =
|
||||||
|
## Create a ``Time`` from a unix timestamp and a nanosecond part.
|
||||||
|
result.seconds = unix
|
||||||
|
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.
|
||||||
subImpl[Duration](a, b)
|
subImpl[Duration](a, b)
|
||||||
|
|
@ -556,18 +607,28 @@ proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} =
|
||||||
doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1)
|
doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1)
|
||||||
addImpl[Time](a, b)
|
addImpl[Time](a, b)
|
||||||
|
|
||||||
|
proc `+=`*(a: var Time, b: Duration) {.operator.} =
|
||||||
|
## Modify ``a`` in place by subtracting ``b``.
|
||||||
|
runnableExamples:
|
||||||
|
var tm = fromUnix(0)
|
||||||
|
tm += initDuration(seconds = 1)
|
||||||
|
doAssert tm == fromUnix(1)
|
||||||
|
|
||||||
|
a = addImpl[Time](a, b)
|
||||||
|
|
||||||
proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} =
|
proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} =
|
||||||
## Subtracts a duration of time from a ``Time``.
|
## Subtracts a duration of time from a ``Time``.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1)
|
doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1)
|
||||||
subImpl[Time](a, b)
|
subImpl[Time](a, b)
|
||||||
|
|
||||||
proc `+=`*(a: var Time, b: Duration) {.operator.} =
|
|
||||||
## Modify ``a`` in place by subtracting ``b``.
|
|
||||||
a = addImpl[Time](a, b)
|
|
||||||
|
|
||||||
proc `-=`*(a: var Time, b: Duration) {.operator.} =
|
proc `-=`*(a: var Time, b: Duration) {.operator.} =
|
||||||
## Modify ``a`` in place by adding ``b``.
|
## Modify ``a`` in place by adding ``b``.
|
||||||
|
runnableExamples:
|
||||||
|
var tm = fromUnix(0)
|
||||||
|
tm -= initDuration(seconds = 1)
|
||||||
|
doAssert tm == fromUnix(-1)
|
||||||
|
|
||||||
a = subImpl[Time](a, b)
|
a = subImpl[Time](a, b)
|
||||||
|
|
||||||
proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} =
|
proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} =
|
||||||
|
|
@ -615,23 +676,8 @@ proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} =
|
||||||
seconds.inc dt.utcOffset
|
seconds.inc dt.utcOffset
|
||||||
result = initTime(seconds, dt.nanosecond)
|
result = initTime(seconds, dt.nanosecond)
|
||||||
|
|
||||||
proc `-`*(dt1, dt2: DateTime): Duration =
|
|
||||||
## Compute the duration between ``dt1`` and ``dt2``.
|
|
||||||
dt1.toTime - dt2.toTime
|
|
||||||
|
|
||||||
proc `<`*(a, b: DateTime): bool =
|
|
||||||
## Returns true iff ``a < b``, that is iff a happened before b.
|
|
||||||
return a.toTime < b.toTime
|
|
||||||
|
|
||||||
proc `<=` * (a, b: DateTime): bool =
|
|
||||||
## Returns true iff ``a <= b``.
|
|
||||||
return a.toTime <= b.toTime
|
|
||||||
|
|
||||||
proc `==`*(a, b: DateTime): bool =
|
|
||||||
## Returns true if ``a == b``, that is if both dates represent the same point in datetime.
|
|
||||||
return a.toTime == b.toTime
|
|
||||||
|
|
||||||
proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
|
proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime =
|
||||||
|
## Create a new ``DateTime`` using ``ZonedTime`` in the specified timezone.
|
||||||
let s = zt.adjTime.seconds
|
let s = zt.adjTime.seconds
|
||||||
let epochday = (if s >= 0: s else: s - (secondsInDay - 1)) div secondsInDay
|
let epochday = (if s >= 0: s else: s - (secondsInDay - 1)) div secondsInDay
|
||||||
var rem = s - epochday * secondsInDay
|
var rem = s - epochday * secondsInDay
|
||||||
|
|
@ -917,11 +963,10 @@ proc `+`*(ti1, ti2: TimeInterval): TimeInterval =
|
||||||
|
|
||||||
proc `-`*(ti: TimeInterval): TimeInterval =
|
proc `-`*(ti: TimeInterval): TimeInterval =
|
||||||
## Reverses a time interval
|
## Reverses a time interval
|
||||||
##
|
runnableExamples:
|
||||||
## .. code-block:: nim
|
let day = -initTimeInterval(hours=24)
|
||||||
##
|
doAssert day.hours == -24
|
||||||
## let day = -initInterval(hours=24)
|
|
||||||
## echo day # -> (milliseconds: 0, seconds: 0, minutes: 0, hours: -24, days: 0, months: 0, years: 0)
|
|
||||||
result = TimeInterval(
|
result = TimeInterval(
|
||||||
nanoseconds: -ti.nanoseconds,
|
nanoseconds: -ti.nanoseconds,
|
||||||
microseconds: -ti.microseconds,
|
microseconds: -ti.microseconds,
|
||||||
|
|
@ -939,13 +984,10 @@ proc `-`*(ti1, ti2: TimeInterval): TimeInterval =
|
||||||
## Subtracts TimeInterval ``ti1`` from ``ti2``.
|
## Subtracts TimeInterval ``ti1`` from ``ti2``.
|
||||||
##
|
##
|
||||||
## Time components are subtracted one-by-one, see output:
|
## Time components are subtracted one-by-one, see output:
|
||||||
##
|
runnableExamples:
|
||||||
## .. code-block:: nim
|
let ti1 = initTimeInterval(hours=24)
|
||||||
## let a = fromUnix(1_000_000_000)
|
let ti2 = initTimeInterval(hours=4)
|
||||||
## let b = fromUnix(1_500_000_000)
|
doAssert (ti1 - ti2) == initTimeInterval(hours=20)
|
||||||
## echo b.toTimeInterval - a.toTimeInterval
|
|
||||||
## # (nanoseconds: 0, microseconds: 0, milliseconds: 0, seconds: -40,
|
|
||||||
## minutes: -6, hours: 1, days: 5, weeks: 0, months: -2, years: 16)
|
|
||||||
|
|
||||||
result = ti1 + (-ti2)
|
result = ti1 + (-ti2)
|
||||||
|
|
||||||
|
|
@ -974,6 +1016,37 @@ proc `$`*(m: Month): string =
|
||||||
"November", "December"]
|
"November", "December"]
|
||||||
return lookup[m]
|
return lookup[m]
|
||||||
|
|
||||||
|
|
||||||
|
proc toParts* (ti: TimeInterval): TimeIntervalParts =
|
||||||
|
## Converts a `TimeInterval` into an array consisting of its time units,
|
||||||
|
## starting with nanoseconds and ending with years
|
||||||
|
##
|
||||||
|
## This procedure is useful for converting ``TimeInterval`` values to strings.
|
||||||
|
## E.g. then you need to implement custom interval printing
|
||||||
|
runnableExamples:
|
||||||
|
var tp = toParts(initTimeInterval(years=1, nanoseconds=123))
|
||||||
|
doAssert tp[Years] == 1
|
||||||
|
doAssert tp[Nanoseconds] == 123
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
for name, value in fieldPairs(ti):
|
||||||
|
result[index.TimeUnit()] = value
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
proc `$`*(ti: TimeInterval): string =
|
||||||
|
## Get string representation of `TimeInterval`
|
||||||
|
runnableExamples:
|
||||||
|
doAssert $initTimeInterval(years=1, nanoseconds=123) == "1 year and 123 nanoseconds"
|
||||||
|
doAssert $initTimeInterval() == "0 nanoseconds"
|
||||||
|
|
||||||
|
var parts: seq[string] = @[]
|
||||||
|
var tiParts = toParts(ti)
|
||||||
|
for unit in countdown(Years, Nanoseconds):
|
||||||
|
if tiParts[unit] != 0:
|
||||||
|
parts.add(stringifyUnit(tiParts[unit], $unit))
|
||||||
|
|
||||||
|
result = humanizeParts(parts)
|
||||||
|
|
||||||
proc nanoseconds*(nanos: int): TimeInterval {.inline.} =
|
proc nanoseconds*(nanos: int): TimeInterval {.inline.} =
|
||||||
## TimeInterval of ``nanos`` nanoseconds.
|
## TimeInterval of ``nanos`` nanoseconds.
|
||||||
initTimeInterval(nanoseconds = nanos)
|
initTimeInterval(nanoseconds = nanos)
|
||||||
|
|
@ -1067,6 +1140,37 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): tuple[adjDur, absDu
|
||||||
minutes = interval.minutes,
|
minutes = interval.minutes,
|
||||||
hours = interval.hours)
|
hours = interval.hours)
|
||||||
|
|
||||||
|
|
||||||
|
proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
||||||
|
hour: HourRange, minute: MinuteRange, second: SecondRange,
|
||||||
|
nanosecond: NanosecondRange, zone: Timezone = local()): DateTime =
|
||||||
|
## Create a new ``DateTime`` in the specified timezone.
|
||||||
|
runnableExamples:
|
||||||
|
let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc())
|
||||||
|
doAssert $dt1 == "2017-03-30T00:00:00+00:00"
|
||||||
|
|
||||||
|
assertValidDate monthday, month, year
|
||||||
|
let dt = DateTime(
|
||||||
|
monthday: monthday,
|
||||||
|
year: year,
|
||||||
|
month: month,
|
||||||
|
hour: hour,
|
||||||
|
minute: minute,
|
||||||
|
second: second,
|
||||||
|
nanosecond: nanosecond
|
||||||
|
)
|
||||||
|
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)
|
||||||
|
|
||||||
|
proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
||||||
|
hour: HourRange, minute: MinuteRange, second: SecondRange,
|
||||||
|
zone: Timezone = local()): DateTime =
|
||||||
|
## Create a new ``DateTime`` in the specified timezone.
|
||||||
|
runnableExamples:
|
||||||
|
let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
doAssert $dt1 == "2017-03-30T00:00:00+00:00"
|
||||||
|
initDateTime(monthday, month, year, hour, minute, second, 0, zone)
|
||||||
|
|
||||||
|
|
||||||
proc `+`*(dt: DateTime, interval: TimeInterval): DateTime =
|
proc `+`*(dt: DateTime, interval: TimeInterval): DateTime =
|
||||||
## Adds ``interval`` to ``dt``. Components from ``interval`` are added
|
## Adds ``interval`` to ``dt``. Components from ``interval`` are added
|
||||||
## in the order of their size, i.e first the ``years`` component, then the ``months``
|
## in the order of their size, i.e first the ``years`` component, then the ``months``
|
||||||
|
|
@ -1100,14 +1204,51 @@ proc `-`*(dt: DateTime, interval: TimeInterval): DateTime =
|
||||||
## Subtract ``interval`` from ``dt``. Components from ``interval`` are subtracted
|
## Subtract ``interval`` from ``dt``. Components from ``interval`` are subtracted
|
||||||
## in the order of their size, i.e first the ``years`` component, then the ``months``
|
## in the order of their size, i.e first the ``years`` component, then the ``months``
|
||||||
## component and so on. The returned ``DateTime`` will have the same timezone as the input.
|
## component and so on. The returned ``DateTime`` will have the same timezone as the input.
|
||||||
|
runnableExamples:
|
||||||
|
let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
doAssert $(dt - 5.days) == "2017-03-25T00:00:00+00:00"
|
||||||
|
|
||||||
dt + (-interval)
|
dt + (-interval)
|
||||||
|
|
||||||
proc `+`*(dt: DateTime, dur: Duration): DateTime =
|
proc `+`*(dt: DateTime, dur: Duration): DateTime =
|
||||||
|
runnableExamples:
|
||||||
|
let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
let dur = initDuration(hours = 5)
|
||||||
|
doAssert $(dt + dur) == "2017-03-30T05:00:00+00:00"
|
||||||
|
|
||||||
(dt.toTime + dur).inZone(dt.timezone)
|
(dt.toTime + dur).inZone(dt.timezone)
|
||||||
|
|
||||||
proc `-`*(dt: DateTime, dur: Duration): DateTime =
|
proc `-`*(dt: DateTime, dur: Duration): DateTime =
|
||||||
|
runnableExamples:
|
||||||
|
let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
let dur = initDuration(days = 5)
|
||||||
|
doAssert $(dt - dur) == "2017-03-25T00:00:00+00:00"
|
||||||
|
|
||||||
(dt.toTime - dur).inZone(dt.timezone)
|
(dt.toTime - dur).inZone(dt.timezone)
|
||||||
|
|
||||||
|
proc `-`*(dt1, dt2: DateTime): Duration =
|
||||||
|
## Compute the duration between ``dt1`` and ``dt2``.
|
||||||
|
runnableExamples:
|
||||||
|
let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
let dt2 = initDateTime(25, mMar, 2017, 00, 00, 00, utc())
|
||||||
|
|
||||||
|
doAssert dt1 - dt2 == initDuration(days = 5)
|
||||||
|
|
||||||
|
dt1.toTime - dt2.toTime
|
||||||
|
|
||||||
|
proc `<`*(a, b: DateTime): bool =
|
||||||
|
## Returns true iff ``a < b``, that is iff a happened before b.
|
||||||
|
return a.toTime < b.toTime
|
||||||
|
|
||||||
|
proc `<=` * (a, b: DateTime): bool =
|
||||||
|
## Returns true iff ``a <= b``.
|
||||||
|
return a.toTime <= b.toTime
|
||||||
|
|
||||||
|
proc `==`*(a, b: DateTime): bool =
|
||||||
|
## Returns true if ``a == b``, that is if both dates represent the same point in datetime.
|
||||||
|
return a.toTime == b.toTime
|
||||||
|
|
||||||
|
|
||||||
proc isStaticInterval(interval: TimeInterval): bool =
|
proc isStaticInterval(interval: TimeInterval): bool =
|
||||||
interval.years == 0 and interval.months == 0 and
|
interval.years == 0 and interval.months == 0 and
|
||||||
interval.days == 0 and interval.weeks == 0
|
interval.days == 0 and interval.weeks == 0
|
||||||
|
|
@ -1121,12 +1262,116 @@ proc evaluateStaticInterval(interval: TimeInterval): Duration =
|
||||||
minutes = interval.minutes,
|
minutes = interval.minutes,
|
||||||
hours = interval.hours)
|
hours = interval.hours)
|
||||||
|
|
||||||
|
proc between*(startDt, endDt:DateTime): TimeInterval =
|
||||||
|
## Evaluate difference between two dates in ``TimeInterval`` format, so, it
|
||||||
|
## will be relative.
|
||||||
|
##
|
||||||
|
## **Warning:** It's not recommended to use ``between`` for ``DateTime's`` in
|
||||||
|
## different ``TimeZone's``.
|
||||||
|
## ``a + between(a, b) == b`` is only guaranteed when ``a`` and ``b`` are in UTC.
|
||||||
|
runnableExamples:
|
||||||
|
var a = initDateTime(year = 2018, month = Month(3), monthday = 25,
|
||||||
|
hour = 0, minute = 59, second = 59, nanosecond = 1,
|
||||||
|
zone = utc()).local
|
||||||
|
var b = initDateTime(year = 2018, month = Month(3), monthday = 25,
|
||||||
|
hour = 1, minute = 1, second = 1, nanosecond = 0,
|
||||||
|
zone = utc()).local
|
||||||
|
doAssert between(a, b) == initTimeInterval(
|
||||||
|
nanoseconds=999, milliseconds=999, microseconds=999, seconds=1, minutes=1)
|
||||||
|
|
||||||
|
a = parse("2018-01-09T00:00:00+00:00", "yyyy-MM-dd'T'HH:mm:sszzz", utc())
|
||||||
|
b = parse("2018-01-10T23:00:00-02:00", "yyyy-MM-dd'T'HH:mm:sszzz")
|
||||||
|
doAssert between(a, b) == initTimeInterval(hours=1, days=2)
|
||||||
|
## Though, here correct answer should be 1 day 25 hours (cause this day in
|
||||||
|
## this tz is actually 26 hours). That's why operating different TZ is
|
||||||
|
## discouraged
|
||||||
|
|
||||||
|
var startDt = startDt.utc()
|
||||||
|
var endDt = endDt.utc()
|
||||||
|
|
||||||
|
if endDt == startDt:
|
||||||
|
return initTimeInterval()
|
||||||
|
elif endDt < startDt:
|
||||||
|
return -between(endDt, startDt)
|
||||||
|
|
||||||
|
var coeffs: array[FixedTimeUnit, int64] = unitWeights
|
||||||
|
var timeParts: array[FixedTimeUnit, int]
|
||||||
|
for unit in Nanoseconds..Weeks:
|
||||||
|
timeParts[unit] = 0
|
||||||
|
|
||||||
|
for unit in Seconds..Days:
|
||||||
|
coeffs[unit] = coeffs[unit] div unitWeights[Seconds]
|
||||||
|
|
||||||
|
var startTimepart = initTime(
|
||||||
|
nanosecond = startDt.nanosecond,
|
||||||
|
unix = startDt.hour * coeffs[Hours] + startDt.minute * coeffs[Minutes] +
|
||||||
|
startDt.second
|
||||||
|
)
|
||||||
|
var endTimepart = initTime(
|
||||||
|
nanosecond = endDt.nanosecond,
|
||||||
|
unix = endDt.hour * coeffs[Hours] + endDt.minute * coeffs[Minutes] +
|
||||||
|
endDt.second
|
||||||
|
)
|
||||||
|
# We wand timeParts for Seconds..Hours be positive, so we'll borrow one day
|
||||||
|
if endTimepart < startTimepart:
|
||||||
|
timeParts[Days] = -1
|
||||||
|
|
||||||
|
let diffTime = endTimepart - startTimepart
|
||||||
|
timeParts[Seconds] = diffTime.seconds.int()
|
||||||
|
#Nanoseconds - preliminary count
|
||||||
|
timeParts[Nanoseconds] = diffTime.nanoseconds
|
||||||
|
for unit in countdown(Milliseconds, Microseconds):
|
||||||
|
timeParts[unit] += timeParts[Nanoseconds] div coeffs[unit].int()
|
||||||
|
timeParts[Nanoseconds] -= timeParts[unit] * coeffs[unit].int()
|
||||||
|
|
||||||
|
#Counting Seconds .. Hours - final, Days - preliminary
|
||||||
|
for unit in countdown(Days, Minutes):
|
||||||
|
timeParts[unit] += timeParts[Seconds] div coeffs[unit].int()
|
||||||
|
# Here is accounted the borrowed day
|
||||||
|
timeParts[Seconds] -= timeParts[unit] * coeffs[unit].int()
|
||||||
|
|
||||||
|
# Set Nanoseconds .. Hours in result
|
||||||
|
result.nanoseconds = timeParts[Nanoseconds]
|
||||||
|
result.microseconds = timeParts[Microseconds]
|
||||||
|
result.milliseconds = timeParts[Milliseconds]
|
||||||
|
result.seconds = timeParts[Seconds]
|
||||||
|
result.minutes = timeParts[Minutes]
|
||||||
|
result.hours = timeParts[Hours]
|
||||||
|
|
||||||
|
#Days
|
||||||
|
if endDt.monthday.int + timeParts[Days] < startDt.monthday.int():
|
||||||
|
if endDt.month > 1.Month:
|
||||||
|
endDt.month -= 1.Month
|
||||||
|
else:
|
||||||
|
endDt.month = 12.Month
|
||||||
|
endDt.year -= 1
|
||||||
|
timeParts[Days] += endDt.monthday.int() + getDaysInMonth(
|
||||||
|
endDt.month, endDt.year) - startDt.monthday.int()
|
||||||
|
else:
|
||||||
|
timeParts[Days] += endDt.monthday.int() -
|
||||||
|
startDt.monthday.int()
|
||||||
|
|
||||||
|
result.days = timeParts[Days]
|
||||||
|
|
||||||
|
#Months
|
||||||
|
if endDt.month < startDt.month:
|
||||||
|
result.months = endDt.month.int() + 12 - startDt.month.int()
|
||||||
|
endDt.year -= 1
|
||||||
|
else:
|
||||||
|
result.months = endDt.month.int() -
|
||||||
|
startDt.month.int()
|
||||||
|
|
||||||
|
# Years
|
||||||
|
result.years = endDt.year - startDt.year
|
||||||
|
|
||||||
proc `+`*(time: Time, interval: TimeInterval): Time =
|
proc `+`*(time: Time, interval: TimeInterval): Time =
|
||||||
## Adds `interval` to `time`.
|
## Adds `interval` to `time`.
|
||||||
## If `interval` contains any years, months, weeks or days the operation
|
## If `interval` contains any years, months, weeks or days the operation
|
||||||
## is performed in the local timezone.
|
## is performed in the local timezone.
|
||||||
##
|
runnableExamples:
|
||||||
## ``echo getTime() + 1.day``
|
let tm = fromUnix(0)
|
||||||
|
doAssert tm + 5.seconds == fromUnix(5)
|
||||||
|
|
||||||
if interval.isStaticInterval:
|
if interval.isStaticInterval:
|
||||||
time + evaluateStaticInterval(interval)
|
time + evaluateStaticInterval(interval)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1136,14 +1381,21 @@ proc `+=`*(time: var Time, interval: TimeInterval) =
|
||||||
## Modifies `time` by adding `interval`.
|
## Modifies `time` by adding `interval`.
|
||||||
## If `interval` contains any years, months, weeks or days the operation
|
## If `interval` contains any years, months, weeks or days the operation
|
||||||
## is performed in the local timezone.
|
## is performed in the local timezone.
|
||||||
|
runnableExamples:
|
||||||
|
var tm = fromUnix(0)
|
||||||
|
tm += 5.seconds
|
||||||
|
doAssert tm == fromUnix(5)
|
||||||
|
|
||||||
time = time + interval
|
time = time + interval
|
||||||
|
|
||||||
proc `-`*(time: Time, interval: TimeInterval): Time =
|
proc `-`*(time: Time, interval: TimeInterval): Time =
|
||||||
## Subtracts `interval` from Time `time`.
|
## Subtracts `interval` from Time `time`.
|
||||||
## If `interval` contains any years, months, weeks or days the operation
|
## If `interval` contains any years, months, weeks or days the operation
|
||||||
## is performed in the local timezone.
|
## is performed in the local timezone.
|
||||||
##
|
runnableExamples:
|
||||||
## ``echo getTime() - 1.day``
|
let tm = fromUnix(5)
|
||||||
|
doAssert tm - 5.seconds == fromUnix(0)
|
||||||
|
|
||||||
if interval.isStaticInterval:
|
if interval.isStaticInterval:
|
||||||
time - evaluateStaticInterval(interval)
|
time - evaluateStaticInterval(interval)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1153,6 +1405,10 @@ proc `-=`*(time: var Time, interval: TimeInterval) =
|
||||||
## Modifies `time` by subtracting `interval`.
|
## Modifies `time` by subtracting `interval`.
|
||||||
## If `interval` contains any years, months, weeks or days the operation
|
## If `interval` contains any years, months, weeks or days the operation
|
||||||
## is performed in the local timezone.
|
## is performed in the local timezone.
|
||||||
|
runnableExamples:
|
||||||
|
var tm = fromUnix(5)
|
||||||
|
tm -= 5.seconds
|
||||||
|
doAssert tm == fromUnix(0)
|
||||||
time = time - interval
|
time = time - interval
|
||||||
|
|
||||||
proc formatToken(dt: DateTime, token: string, buf: var string) =
|
proc formatToken(dt: DateTime, token: string, buf: var string) =
|
||||||
|
|
@ -1274,6 +1530,12 @@ proc formatToken(dt: DateTime, token: string, buf: var string) =
|
||||||
buf.add(':')
|
buf.add(':')
|
||||||
if minutes < 10: buf.add('0')
|
if minutes < 10: buf.add('0')
|
||||||
buf.add($minutes)
|
buf.add($minutes)
|
||||||
|
of "fff":
|
||||||
|
buf.add(intToStr(convert(Nanoseconds, Milliseconds, dt.nanosecond), 3))
|
||||||
|
of "ffffff":
|
||||||
|
buf.add(intToStr(convert(Nanoseconds, Microseconds, dt.nanosecond), 6))
|
||||||
|
of "fffffffff":
|
||||||
|
buf.add(intToStr(dt.nanosecond, 9))
|
||||||
of "":
|
of "":
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
|
|
@ -1284,40 +1546,46 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
|
||||||
## This procedure formats `dt` as specified by `f`. The following format
|
## This procedure formats `dt` as specified by `f`. The following format
|
||||||
## specifiers are available:
|
## specifiers are available:
|
||||||
##
|
##
|
||||||
## ========== ================================================================================= ================================================
|
## ============ ================================================================================= ================================================
|
||||||
## Specifier Description Example
|
## Specifier Description Example
|
||||||
## ========== ================================================================================= ================================================
|
## ============ ================================================================================= ================================================
|
||||||
## d Numeric value of the day of the month, it will be one or two digits long. ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
|
## d Numeric value of the day of the month, it will be one or two digits long. ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
|
||||||
## dd Same as above, but always two digits. ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
|
## dd Same as above, but always two digits. ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
|
||||||
## ddd Three letter string which indicates the day of the week. ``Saturday -> Sat``, ``Monday -> Mon``
|
## ddd Three letter string which indicates the day of the week. ``Saturday -> Sat``, ``Monday -> Mon``
|
||||||
## dddd Full string for the day of the week. ``Saturday -> Saturday``, ``Monday -> Monday``
|
## dddd Full string for the day of the week. ``Saturday -> Saturday``, ``Monday -> Monday``
|
||||||
## h The hours in one digit if possible. Ranging from 0-12. ``5pm -> 5``, ``2am -> 2``
|
## h The hours in one digit if possible. Ranging from 0-12. ``5pm -> 5``, ``2am -> 2``
|
||||||
## hh The hours in two digits always. If the hour is one digit 0 is prepended. ``5pm -> 05``, ``11am -> 11``
|
## hh The hours in two digits always. If the hour is one digit 0 is prepended. ``5pm -> 05``, ``11am -> 11``
|
||||||
## H The hours in one digit if possible, randing from 0-24. ``5pm -> 17``, ``2am -> 2``
|
## H The hours in one digit if possible, randing from 0-24. ``5pm -> 17``, ``2am -> 2``
|
||||||
## HH The hours in two digits always. 0 is prepended if the hour is one digit. ``5pm -> 17``, ``2am -> 02``
|
## HH The hours in two digits always. 0 is prepended if the hour is one digit. ``5pm -> 17``, ``2am -> 02``
|
||||||
## m The minutes in 1 digit if possible. ``5:30 -> 30``, ``2:01 -> 1``
|
## m The minutes in 1 digit if possible. ``5:30 -> 30``, ``2:01 -> 1``
|
||||||
## mm Same as above but always 2 digits, 0 is prepended if the minute is one digit. ``5:30 -> 30``, ``2:01 -> 01``
|
## mm Same as above but always 2 digits, 0 is prepended if the minute is one digit. ``5:30 -> 30``, ``2:01 -> 01``
|
||||||
## M The month in one digit if possible. ``September -> 9``, ``December -> 12``
|
## M The month in one digit if possible. ``September -> 9``, ``December -> 12``
|
||||||
## MM The month in two digits always. 0 is prepended. ``September -> 09``, ``December -> 12``
|
## MM The month in two digits always. 0 is prepended. ``September -> 09``, ``December -> 12``
|
||||||
## MMM Abbreviated three-letter form of the month. ``September -> Sep``, ``December -> Dec``
|
## MMM Abbreviated three-letter form of the month. ``September -> Sep``, ``December -> Dec``
|
||||||
## MMMM Full month string, properly capitalized. ``September -> September``
|
## MMMM Full month string, properly capitalized. ``September -> September``
|
||||||
## s Seconds as one digit if possible. ``00:00:06 -> 6``
|
## s Seconds as one digit if possible. ``00:00:06 -> 6``
|
||||||
## ss Same as above but always two digits. 0 is prepended. ``00:00:06 -> 06``
|
## ss Same as above but always two digits. 0 is prepended. ``00:00:06 -> 06``
|
||||||
## t ``A`` when time is in the AM. ``P`` when time is in the PM.
|
## t ``A`` when time is in the AM. ``P`` when time is in the PM.
|
||||||
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
|
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
|
||||||
## y(yyyy) This displays the year to different digits. You most likely only want 2 or 4 'y's
|
## y(yyyy) This displays the year to different digits. You most likely only want 2 or 4 'y's
|
||||||
## yy Displays the year to two digits. ``2012 -> 12``
|
## yy Displays the year to two digits. ``2012 -> 12``
|
||||||
## yyyy Displays the year to four digits. ``2012 -> 2012``
|
## yyyy Displays the year to four digits. ``2012 -> 2012``
|
||||||
## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5``
|
## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5``
|
||||||
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
|
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
|
||||||
## zzz Same as above but with ``:mm`` where *mm* represents minutes. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
|
## zzz Same as above but with ``:mm`` where *mm* represents minutes. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
|
||||||
## ========== ================================================================================= ================================================
|
## fff Milliseconds display ``1000000 nanoseconds -> 1``
|
||||||
|
## ffffff Microseconds display ``1000000 nanoseconds -> 1000``
|
||||||
|
## fffffffff Nanoseconds display ``1000000 nanoseconds -> 1000000``
|
||||||
|
## ============ ================================================================================= ================================================
|
||||||
##
|
##
|
||||||
## Other strings can be inserted by putting them in ``''``. For example
|
## Other strings can be inserted by putting them in ``''``. For example
|
||||||
## ``hh'->'mm`` will give ``01->56``. The following characters can be
|
## ``hh'->'mm`` will give ``01->56``. The following characters can be
|
||||||
## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
|
## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
|
||||||
## ``,``. However you don't need to necessarily separate format specifiers, a
|
## ``,``. However you don't need to necessarily separate format specifiers, a
|
||||||
## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
|
## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
|
||||||
|
runnableExamples:
|
||||||
|
let dt = initDateTime(01, mJan, 2000, 12, 00, 00, 01, utc())
|
||||||
|
doAssert format(dt, "yyyy-MM-dd'T'HH:mm:ss'.'fffffffffzzz") == "2000-01-01T12:00:00.000000001+00:00"
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -1348,9 +1616,25 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
|
||||||
inc(i)
|
inc(i)
|
||||||
formatToken(dt, currentF, result)
|
formatToken(dt, currentF, result)
|
||||||
|
|
||||||
|
proc format*(time: Time, f: string, zone_info: proc(t: Time): DateTime): string {.tags: [].} =
|
||||||
|
## converts a `Time` value to a string representation. It will use format from
|
||||||
|
## ``format(dt: DateTime, f: string)``.
|
||||||
|
runnableExamples:
|
||||||
|
var dt = initDateTime(01, mJan, 1970, 00, 00, 00, local())
|
||||||
|
var tm = dt.toTime()
|
||||||
|
doAssert format(tm, "yyyy-MM-dd'T'HH:mm:ss", local) == "1970-01-01T00:00:00"
|
||||||
|
dt = initDateTime(01, mJan, 1970, 00, 00, 00, utc())
|
||||||
|
tm = dt.toTime()
|
||||||
|
doAssert format(tm, "yyyy-MM-dd'T'HH:mm:ss", utc) == "1970-01-01T00:00:00"
|
||||||
|
|
||||||
|
zone_info(time).format(f)
|
||||||
|
|
||||||
proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
|
proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
|
||||||
## Converts a `DateTime` object to a string representation.
|
## Converts a `DateTime` object to a string representation.
|
||||||
## It uses the format ``yyyy-MM-dd'T'HH-mm-sszzz``.
|
## It uses the format ``yyyy-MM-dd'T'HH-mm-sszzz``.
|
||||||
|
runnableExamples:
|
||||||
|
let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc())
|
||||||
|
doAssert $dt == "2000-01-01T12:00:00+00:00"
|
||||||
try:
|
try:
|
||||||
result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") # todo: optimize this
|
result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") # todo: optimize this
|
||||||
except ValueError: assert false # cannot happen because format string is valid
|
except ValueError: assert false # cannot happen because format string is valid
|
||||||
|
|
@ -1358,6 +1642,10 @@ proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
|
||||||
proc `$`*(time: Time): string {.tags: [], raises: [], benign.} =
|
proc `$`*(time: Time): string {.tags: [], raises: [], benign.} =
|
||||||
## converts a `Time` value to a string representation. It will use the local
|
## converts a `Time` value to a string representation. It will use the local
|
||||||
## time zone and use the format ``yyyy-MM-dd'T'HH-mm-sszzz``.
|
## time zone and use the format ``yyyy-MM-dd'T'HH-mm-sszzz``.
|
||||||
|
runnableExamples:
|
||||||
|
let dt = initDateTime(01, mJan, 1970, 00, 00, 00, local())
|
||||||
|
let tm = dt.toTime()
|
||||||
|
doAssert $tm == "1970-01-01T00:00:00" & format(dt, "zzz")
|
||||||
$time.local
|
$time.local
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
@ -1574,6 +1862,11 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
||||||
j += 4
|
j += 4
|
||||||
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
||||||
j += 2
|
j += 2
|
||||||
|
of "fff", "ffffff", "fffffffff":
|
||||||
|
var numStr = ""
|
||||||
|
let n = parseWhile(value[j..len(value) - 1], numStr, {'0'..'9'})
|
||||||
|
dt.nanosecond = parseInt(numStr) * (10 ^ (9 - n))
|
||||||
|
j += n
|
||||||
else:
|
else:
|
||||||
# Ignore the token and move forward in the value string by the same length
|
# Ignore the token and move forward in the value string by the same length
|
||||||
j += token.len
|
j += token.len
|
||||||
|
|
@ -1587,39 +1880,44 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
|
||||||
## parsed, then the input will be assumed to be specified in the `zone` timezone
|
## parsed, then the input will be assumed to be specified in the `zone` timezone
|
||||||
## already, so no timezone conversion will be done in that case.
|
## already, so no timezone conversion will be done in that case.
|
||||||
##
|
##
|
||||||
## ========== ================================================================================= ================================================
|
## ======================= ================================================================================= ================================================
|
||||||
## Specifier Description Example
|
## Specifier Description Example
|
||||||
## ========== ================================================================================= ================================================
|
## ======================= ================================================================================= ================================================
|
||||||
## d Numeric value of the day of the month, it will be one or two digits long. ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
|
## d Numeric value of the day of the month, it will be one or two digits long. ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
|
||||||
## dd Same as above, but always two digits. ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
|
## dd Same as above, but always two digits. ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
|
||||||
## ddd Three letter string which indicates the day of the week. ``Saturday -> Sat``, ``Monday -> Mon``
|
## ddd Three letter string which indicates the day of the week. ``Saturday -> Sat``, ``Monday -> Mon``
|
||||||
## dddd Full string for the day of the week. ``Saturday -> Saturday``, ``Monday -> Monday``
|
## dddd Full string for the day of the week. ``Saturday -> Saturday``, ``Monday -> Monday``
|
||||||
## h The hours in one digit if possible. Ranging from 0-12. ``5pm -> 5``, ``2am -> 2``
|
## h The hours in one digit if possible. Ranging from 0-12. ``5pm -> 5``, ``2am -> 2``
|
||||||
## hh The hours in two digits always. If the hour is one digit 0 is prepended. ``5pm -> 05``, ``11am -> 11``
|
## hh The hours in two digits always. If the hour is one digit 0 is prepended. ``5pm -> 05``, ``11am -> 11``
|
||||||
## H The hours in one digit if possible, randing from 0-24. ``5pm -> 17``, ``2am -> 2``
|
## H The hours in one digit if possible, randing from 0-24. ``5pm -> 17``, ``2am -> 2``
|
||||||
## HH The hours in two digits always. 0 is prepended if the hour is one digit. ``5pm -> 17``, ``2am -> 02``
|
## HH The hours in two digits always. 0 is prepended if the hour is one digit. ``5pm -> 17``, ``2am -> 02``
|
||||||
## m The minutes in 1 digit if possible. ``5:30 -> 30``, ``2:01 -> 1``
|
## m The minutes in 1 digit if possible. ``5:30 -> 30``, ``2:01 -> 1``
|
||||||
## mm Same as above but always 2 digits, 0 is prepended if the minute is one digit. ``5:30 -> 30``, ``2:01 -> 01``
|
## mm Same as above but always 2 digits, 0 is prepended if the minute is one digit. ``5:30 -> 30``, ``2:01 -> 01``
|
||||||
## M The month in one digit if possible. ``September -> 9``, ``December -> 12``
|
## M The month in one digit if possible. ``September -> 9``, ``December -> 12``
|
||||||
## MM The month in two digits always. 0 is prepended. ``September -> 09``, ``December -> 12``
|
## MM The month in two digits always. 0 is prepended. ``September -> 09``, ``December -> 12``
|
||||||
## MMM Abbreviated three-letter form of the month. ``September -> Sep``, ``December -> Dec``
|
## MMM Abbreviated three-letter form of the month. ``September -> Sep``, ``December -> Dec``
|
||||||
## MMMM Full month string, properly capitalized. ``September -> September``
|
## MMMM Full month string, properly capitalized. ``September -> September``
|
||||||
## s Seconds as one digit if possible. ``00:00:06 -> 6``
|
## s Seconds as one digit if possible. ``00:00:06 -> 6``
|
||||||
## ss Same as above but always two digits. 0 is prepended. ``00:00:06 -> 06``
|
## ss Same as above but always two digits. 0 is prepended. ``00:00:06 -> 06``
|
||||||
## t ``A`` when time is in the AM. ``P`` when time is in the PM.
|
## t ``A`` when time is in the AM. ``P`` when time is in the PM.
|
||||||
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
|
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
|
||||||
## yy Displays the year to two digits. ``2012 -> 12``
|
## yy Displays the year to two digits. ``2012 -> 12``
|
||||||
## yyyy Displays the year to four digits. ``2012 -> 2012``
|
## yyyy Displays the year to four digits. ``2012 -> 2012``
|
||||||
## z Displays the timezone offset from UTC. ``Z`` is parsed as ``+0`` ``GMT+7 -> +7``, ``GMT-5 -> -5``
|
## z Displays the timezone offset from UTC. ``Z`` is parsed as ``+0`` ``GMT+7 -> +7``, ``GMT-5 -> -5``
|
||||||
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
|
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
|
||||||
## zzz Same as above but with ``:mm`` where *mm* represents minutes. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
|
## zzz Same as above but with ``:mm`` where *mm* represents minutes. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
|
||||||
## ========== ================================================================================= ================================================
|
## fff/ffffff/fffffffff for consistency with format - nanoseconds ``1 -> 1 nanosecond``
|
||||||
|
## ======================= ================================================================================= ================================================
|
||||||
##
|
##
|
||||||
## Other strings can be inserted by putting them in ``''``. For example
|
## Other strings can be inserted by putting them in ``''``. For example
|
||||||
## ``hh'->'mm`` will give ``01->56``. The following characters can be
|
## ``hh'->'mm`` will give ``01->56``. The following characters can be
|
||||||
## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
|
## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
|
||||||
## ``,``. However you don't need to necessarily separate format specifiers, a
|
## ``,``. However you don't need to necessarily separate format specifiers, a
|
||||||
## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
|
## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
|
||||||
|
runnableExamples:
|
||||||
|
let tStr = "1970-01-01T00:00:00.0+00:00"
|
||||||
|
doAssert parse(tStr, "yyyy-MM-dd'T'HH:mm:ss.fffzzz") == fromUnix(0).utc
|
||||||
|
|
||||||
var i = 0 # pointer for format string
|
var i = 0 # pointer for format string
|
||||||
var j = 0 # pointer for value string
|
var j = 0 # pointer for value string
|
||||||
var token = ""
|
var token = ""
|
||||||
|
|
@ -1667,6 +1965,13 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
|
||||||
# Otherwise convert to `zone`
|
# Otherwise convert to `zone`
|
||||||
result = dt.toTime.inZone(zone)
|
result = dt.toTime.inZone(zone)
|
||||||
|
|
||||||
|
proc parseTime*(value, layout: string, zone: Timezone): Time =
|
||||||
|
## Simple wrapper for parsing string to time
|
||||||
|
runnableExamples:
|
||||||
|
let tStr = "1970-01-01T00:00:00+00:00"
|
||||||
|
doAssert parseTime(tStr, "yyyy-MM-dd'T'HH:mm:sszzz", local()) == fromUnix(0)
|
||||||
|
parse(value, layout, zone).toTime()
|
||||||
|
|
||||||
proc countLeapYears*(yearSpan: int): int =
|
proc countLeapYears*(yearSpan: int): int =
|
||||||
## Returns the number of leap years spanned by a given number of years.
|
## Returns the number of leap years spanned by a given number of years.
|
||||||
##
|
##
|
||||||
|
|
@ -1695,41 +2000,19 @@ proc toTimeInterval*(time: Time): TimeInterval =
|
||||||
## Converts a Time to a TimeInterval.
|
## Converts a Time to a TimeInterval.
|
||||||
##
|
##
|
||||||
## To be used when diffing times.
|
## To be used when diffing times.
|
||||||
##
|
runnableExamples:
|
||||||
## .. code-block:: nim
|
let a = fromUnix(10)
|
||||||
## let a = fromSeconds(1_000_000_000)
|
let dt = initDateTime(01, mJan, 1970, 00, 00, 00, local())
|
||||||
## let b = fromSeconds(1_500_000_000)
|
doAssert a.toTimeInterval() == initTimeInterval(
|
||||||
## echo a, " ", b # real dates
|
years=1970, days=1, seconds=10, hours=convert(
|
||||||
## echo a.toTimeInterval # meaningless value, don't use it by itself
|
Seconds, Hours, -dt.utcOffset
|
||||||
## echo b.toTimeInterval - a.toTimeInterval
|
)
|
||||||
## # (nanoseconds: 0, microseconds: 0, milliseconds: 0, seconds: -40,
|
)
|
||||||
## minutes: -6, hours: 1, days: 5, weeks: 0, months: -2, years: 16)
|
|
||||||
var dt = time.local
|
var dt = time.local
|
||||||
initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour,
|
initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour,
|
||||||
dt.monthday, 0, dt.month.ord - 1, dt.year)
|
dt.monthday, 0, dt.month.ord - 1, dt.year)
|
||||||
|
|
||||||
proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
|
||||||
hour: HourRange, minute: MinuteRange, second: SecondRange,
|
|
||||||
nanosecond: NanosecondRange, zone: Timezone = local()): DateTime =
|
|
||||||
## Create a new ``DateTime`` in the specified timezone.
|
|
||||||
assertValidDate monthday, month, year
|
|
||||||
let dt = DateTime(
|
|
||||||
monthday: monthday,
|
|
||||||
year: year,
|
|
||||||
month: month,
|
|
||||||
hour: hour,
|
|
||||||
minute: minute,
|
|
||||||
second: second,
|
|
||||||
nanosecond: nanosecond
|
|
||||||
)
|
|
||||||
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)
|
|
||||||
|
|
||||||
proc initDateTime*(monthday: MonthdayRange, month: Month, year: int,
|
|
||||||
hour: HourRange, minute: MinuteRange, second: SecondRange,
|
|
||||||
zone: Timezone = local()): DateTime =
|
|
||||||
## Create a new ``DateTime`` in the specified timezone.
|
|
||||||
initDateTime(monthday, month, year, hour, minute, second, 0, zone)
|
|
||||||
|
|
||||||
when not defined(JS):
|
when not defined(JS):
|
||||||
type
|
type
|
||||||
Clock {.importc: "clock_t".} = distinct int
|
Clock {.importc: "clock_t".} = distinct int
|
||||||
|
|
@ -1747,11 +2030,14 @@ when not defined(JS):
|
||||||
## The value of the result has no meaning.
|
## The value of the result has no meaning.
|
||||||
## To generate useful timing values, take the difference between
|
## To generate useful timing values, take the difference between
|
||||||
## the results of two ``cpuTime`` calls:
|
## the results of two ``cpuTime`` calls:
|
||||||
##
|
runnableExamples:
|
||||||
## .. code-block:: nim
|
var t0 = cpuTime()
|
||||||
## var t0 = cpuTime()
|
# some useless work here (calculate fibonacci)
|
||||||
## doWork()
|
var fib = @[0, 1, 1]
|
||||||
## echo "CPU time [s] ", cpuTime() - t0
|
for i in 1..10:
|
||||||
|
fib.add(fib[^1] + fib[^2])
|
||||||
|
echo "CPU time [s] ", cpuTime() - t0
|
||||||
|
echo "Fib is [s] ", fib
|
||||||
result = toFloat(int(getClock())) / toFloat(clocksPerSec)
|
result = toFloat(int(getClock())) / toFloat(clocksPerSec)
|
||||||
|
|
||||||
proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} =
|
proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} =
|
||||||
|
|
@ -1853,15 +2139,14 @@ proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.}
|
||||||
proc timeInfoToTime*(dt: DateTime): Time {.tags: [], benign, deprecated.} =
|
proc timeInfoToTime*(dt: DateTime): Time {.tags: [], benign, deprecated.} =
|
||||||
## Converts a broken-down time structure to calendar time representation.
|
## Converts a broken-down time structure to calendar time representation.
|
||||||
##
|
##
|
||||||
## **Warning:** This procedure is deprecated since version 0.14.0.
|
## **Deprecated since v0.14.0:** use ``toTime`` instead.
|
||||||
## Use ``toTime`` instead.
|
|
||||||
dt.toTime
|
dt.toTime
|
||||||
|
|
||||||
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
|
## get the milliseconds from the start of the program.
|
||||||
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
|
## **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
|
||||||
|
|
@ -1875,19 +2160,19 @@ else:
|
||||||
proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} =
|
proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} =
|
||||||
## Converts a Time to a TimeInterval.
|
## Converts a Time to a TimeInterval.
|
||||||
##
|
##
|
||||||
## **Warning:** This procedure is deprecated since version 0.14.0.
|
## **Deprecated since v0.14.0:** use ``toTimeInterval`` instead.
|
||||||
## Use ``toTimeInterval`` instead.
|
|
||||||
# Milliseconds not available from Time
|
# Milliseconds not available from Time
|
||||||
t.toTimeInterval()
|
t.toTimeInterval()
|
||||||
|
|
||||||
proc getDayOfWeek*(day, month, year: int): WeekDay {.tags: [], raises: [], benign, deprecated.} =
|
proc getDayOfWeek*(day, month, year: int): WeekDay {.tags: [], raises: [], benign, deprecated.} =
|
||||||
## **Warning:** This procedure is deprecated since version 0.18.0.
|
## **Deprecated since v0.18.0:** use
|
||||||
|
## ``getDayOfWeek(monthday: MonthdayRange; month: Month; year: int)`` instead.
|
||||||
getDayOfWeek(day, month.Month, year)
|
getDayOfWeek(day, month.Month, year)
|
||||||
|
|
||||||
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.
|
||||||
## **Warning:** This procedure is deprecated since version 0.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
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
## Note: Import ``std/sha1`` to use this module
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
const Sha1DigestSize = 20
|
const Sha1DigestSize = 20
|
||||||
|
|
|
||||||
|
|
@ -1523,7 +1523,6 @@ const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(n
|
||||||
when not defined(JS) and not defined(nimscript) and hostOS != "standalone":
|
when not defined(JS) and not defined(nimscript) and hostOS != "standalone":
|
||||||
include "system/cgprocs"
|
include "system/cgprocs"
|
||||||
when not defined(JS) and not defined(nimscript) and hasAlloc:
|
when not defined(JS) and not defined(nimscript) and hasAlloc:
|
||||||
proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline, benign.}
|
|
||||||
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
|
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
|
||||||
|
|
||||||
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
||||||
|
|
@ -2639,6 +2638,11 @@ when not defined(nimscript) and hasAlloc:
|
||||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||||
## see the documentation of `GC_ref`.
|
## see the documentation of `GC_ref`.
|
||||||
|
|
||||||
|
when not defined(JS) and not defined(nimscript) and hasAlloc:
|
||||||
|
proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.}
|
||||||
|
## Expands operating GC stack range to `theStackBottom`. Does nothing
|
||||||
|
## if current stack bottom is already lower than `theStackBottom`.
|
||||||
|
|
||||||
else:
|
else:
|
||||||
template GC_disable* =
|
template GC_disable* =
|
||||||
{.warning: "GC_disable is a no-op in JavaScript".}
|
{.warning: "GC_disable is a no-op in JavaScript".}
|
||||||
|
|
@ -2898,16 +2902,16 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
# WARNING: This is very fragile! An array size of 8 does not work on my
|
# WARNING: This is very fragile! An array size of 8 does not work on my
|
||||||
# Linux 64bit system. -- That's because the stack direction is the other
|
# Linux 64bit system. -- That's because the stack direction is the other
|
||||||
# way round.
|
# way round.
|
||||||
when declared(setStackBottom):
|
when declared(nimGC_setStackBottom):
|
||||||
var locals {.volatile.}: pointer
|
var locals {.volatile.}: pointer
|
||||||
locals = addr(locals)
|
locals = addr(locals)
|
||||||
setStackBottom(locals)
|
nimGC_setStackBottom(locals)
|
||||||
|
|
||||||
proc initStackBottomWith(locals: pointer) {.inline, compilerproc.} =
|
proc initStackBottomWith(locals: pointer) {.inline, compilerproc.} =
|
||||||
# We need to keep initStackBottom around for now to avoid
|
# We need to keep initStackBottom around for now to avoid
|
||||||
# bootstrapping problems.
|
# bootstrapping problems.
|
||||||
when declared(setStackBottom):
|
when declared(nimGC_setStackBottom):
|
||||||
setStackBottom(locals)
|
nimGC_setStackBottom(locals)
|
||||||
|
|
||||||
{.push profiler: off.}
|
{.push profiler: off.}
|
||||||
var
|
var
|
||||||
|
|
@ -3443,6 +3447,14 @@ when not defined(nimNoArrayToString):
|
||||||
## generic ``$`` operator for arrays that is lifted from the components
|
## generic ``$`` operator for arrays that is lifted from the components
|
||||||
collectionToString(x, "[", ", ", "]")
|
collectionToString(x, "[", ", ", "]")
|
||||||
|
|
||||||
|
proc `$`*[T](x: openarray[T]): string =
|
||||||
|
## generic ``$`` operator for openarrays that is lifted from the components
|
||||||
|
## of `x`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]"
|
||||||
|
collectionToString(x, "[", ", ", "]")
|
||||||
|
|
||||||
proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
|
proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
|
||||||
## a shorthand for ``echo(errormsg); quit(errorcode)``.
|
## a shorthand for ``echo(errormsg); quit(errorcode)``.
|
||||||
echo(errormsg)
|
echo(errormsg)
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ when declared(threadType):
|
||||||
if threadType == ThreadType.None:
|
if threadType == ThreadType.None:
|
||||||
initAllocator()
|
initAllocator()
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
setStackBottom(addr(stackTop))
|
nimGC_setStackBottom(addr(stackTop))
|
||||||
initGC()
|
initGC()
|
||||||
threadType = ThreadType.ForeignThread
|
threadType = ThreadType.ForeignThread
|
||||||
|
|
||||||
|
|
@ -257,7 +257,7 @@ when nimCoroutines:
|
||||||
gch.activeStack.setPosition(addr(sp))
|
gch.activeStack.setPosition(addr(sp))
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc setStackBottom(theStackBottom: pointer) =
|
proc nimGC_setStackBottom(theStackBottom: pointer) =
|
||||||
# Initializes main stack of the thread.
|
# Initializes main stack of the thread.
|
||||||
when nimCoroutines:
|
when nimCoroutines:
|
||||||
if gch.stack.next == nil:
|
if gch.stack.next == nil:
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ proc getFreeMem*(r: MemRegion): int = r.remaining
|
||||||
proc getTotalMem*(r: MemRegion): int =
|
proc getTotalMem*(r: MemRegion): int =
|
||||||
result = r.totalSize
|
result = r.totalSize
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc nimGCref(x: pointer) {.compilerProc.} = discard
|
proc nimGCref(x: pointer) {.compilerProc.} = discard
|
||||||
proc nimGCunref(x: pointer) {.compilerProc.} = discard
|
proc nimGCunref(x: pointer) {.compilerProc.} = discard
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ when defined(boehmgc):
|
||||||
proc getFreeMem(): int = return boehmGetFreeBytes()
|
proc getFreeMem(): int = return boehmGetFreeBytes()
|
||||||
proc getTotalMem(): int = return boehmGetHeapSize()
|
proc getTotalMem(): int = return boehmGetHeapSize()
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
boehmGCinit()
|
boehmGCinit()
|
||||||
|
|
@ -305,7 +305,7 @@ elif defined(gogc):
|
||||||
goRuntime_ReadMemStats(addr mstats)
|
goRuntime_ReadMemStats(addr mstats)
|
||||||
result = int(mstats.sys)
|
result = int(mstats.sys)
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc alloc(size: Natural): pointer =
|
proc alloc(size: Natural): pointer =
|
||||||
result = c_malloc(size)
|
result = c_malloc(size)
|
||||||
|
|
@ -449,7 +449,7 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
proc getFreeMem(): int = discard
|
proc getFreeMem(): int = discard
|
||||||
proc getTotalMem(): int = discard
|
proc getTotalMem(): int = discard
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc initGC() = discard
|
proc initGC() = discard
|
||||||
|
|
||||||
|
|
@ -523,7 +523,7 @@ elif defined(nogc):
|
||||||
proc growObj(old: pointer, newsize: int): pointer =
|
proc growObj(old: pointer, newsize: int): pointer =
|
||||||
result = realloc(old, newsize)
|
result = realloc(old, newsize)
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -440,7 +440,7 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
|
||||||
threadProcWrapDispatch[TArg]
|
threadProcWrapDispatch[TArg]
|
||||||
when not hasSharedHeap:
|
when not hasSharedHeap:
|
||||||
# init the GC for refc/markandsweep
|
# init the GC for refc/markandsweep
|
||||||
setStackBottom(addr(p))
|
nimGC_setStackBottom(addr(p))
|
||||||
initGC()
|
initGC()
|
||||||
when declared(threadType):
|
when declared(threadType):
|
||||||
threadType = ThreadType.NimThread
|
threadType = ThreadType.NimThread
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ the latest release, check out [Nim's website][nim-site].
|
||||||
Also where most development decisions get made.
|
Also where most development decisions get made.
|
||||||
* [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There
|
* [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There
|
||||||
is a bridge between Gitter and the IRC channel.
|
is a bridge between Gitter and the IRC channel.
|
||||||
|
* [Telegram][nim-telegram] - an additional place to discuss Nim in real-time. There
|
||||||
|
is the official Telegram channel.
|
||||||
* [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related
|
* [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related
|
||||||
topics that includes posts about Nim.
|
topics that includes posts about Nim.
|
||||||
* [Github Wiki][nim-wiki] - Misc user-contributed content.
|
* [Github Wiki][nim-wiki] - Misc user-contributed content.
|
||||||
|
|
@ -180,7 +182,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim.
|
||||||
|
|
||||||
Please read the [copying.txt](copying.txt) file for more details.
|
Please read the [copying.txt](copying.txt) file for more details.
|
||||||
|
|
||||||
Copyright © 2006-2017 Andreas Rumpf, all rights reserved.
|
Copyright © 2006-2018 Andreas Rumpf, all rights reserved.
|
||||||
|
|
||||||
[nim-site]: https://nim-lang.org
|
[nim-site]: https://nim-lang.org
|
||||||
[nim-forum]: https://forum.nim-lang.org
|
[nim-forum]: https://forum.nim-lang.org
|
||||||
|
|
@ -192,6 +194,7 @@ Copyright © 2006-2017 Andreas Rumpf, all rights reserved.
|
||||||
[nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim
|
[nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim
|
||||||
[nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15
|
[nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15
|
||||||
[nim-gitter]: https://gitter.im/nim-lang/Nim
|
[nim-gitter]: https://gitter.im/nim-lang/Nim
|
||||||
|
[nim-telegram]: https://t.me/nim_lang
|
||||||
[nim-bountysource]: https://www.bountysource.com/teams/nim
|
[nim-bountysource]: https://www.bountysource.com/teams/nim
|
||||||
[nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
|
[nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
|
||||||
[nimble-repo]: https://github.com/nim-lang/nimble
|
[nimble-repo]: https://github.com/nim-lang/nimble
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,5 @@ allowing you to create commercial applications.
|
||||||
|
|
||||||
Read copying.txt for more details.
|
Read copying.txt for more details.
|
||||||
|
|
||||||
Copyright (c) 2006-2016 Andreas Rumpf.
|
Copyright (c) 2006-2018 Andreas Rumpf.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
|
||||||
45
tests/array/t7818.nim
Normal file
45
tests/array/t7818.nim
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
discard """
|
||||||
|
msg: '''BracketExpr
|
||||||
|
Sym "array"
|
||||||
|
Infix
|
||||||
|
Ident ".."
|
||||||
|
IntLit 0
|
||||||
|
IntLit 2
|
||||||
|
BracketExpr
|
||||||
|
Sym "Vehicle"
|
||||||
|
Sym "int"
|
||||||
|
---------
|
||||||
|
BracketExpr
|
||||||
|
Sym "array"
|
||||||
|
Infix
|
||||||
|
Ident ".."
|
||||||
|
IntLit 0
|
||||||
|
IntLit 2
|
||||||
|
BracketExpr
|
||||||
|
Sym "Vehicle"
|
||||||
|
Sym "int"
|
||||||
|
---------'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #7818
|
||||||
|
# this is not a macro bug, but array construction bug
|
||||||
|
# I use macro to avoid object slicing
|
||||||
|
# see #7712 and #7637
|
||||||
|
import macros
|
||||||
|
|
||||||
|
type
|
||||||
|
Vehicle[T] = object of RootObj
|
||||||
|
tire: T
|
||||||
|
Car[T] = object of Vehicle[T]
|
||||||
|
Bike[T] = object of Vehicle[T]
|
||||||
|
|
||||||
|
macro peek(n: typed): untyped =
|
||||||
|
echo getTypeImpl(n).treeRepr
|
||||||
|
echo "---------"
|
||||||
|
|
||||||
|
var v = Vehicle[int](tire: 3)
|
||||||
|
var c = Car[int](tire: 4)
|
||||||
|
var b = Bike[int](tire: 2)
|
||||||
|
|
||||||
|
peek([c, b, v])
|
||||||
|
peek([v, c, b])
|
||||||
8
tests/misc/åäö.nim
Normal file
8
tests/misc/åäö.nim
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
discard """
|
||||||
|
action: run
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Tests that module names can contain multi byte characters
|
||||||
|
|
||||||
|
let a = 1
|
||||||
|
doAssert åäö.a == 1
|
||||||
|
|
@ -11,3 +11,12 @@ proc `$`(o: Obj): string = "foobar"
|
||||||
var o: Obj
|
var o: Obj
|
||||||
doAssert fmt"{o}" == "foobar"
|
doAssert fmt"{o}" == "foobar"
|
||||||
doAssert fmt"{o:10}" == "foobar "
|
doAssert fmt"{o:10}" == "foobar "
|
||||||
|
|
||||||
|
# see issue #7932
|
||||||
|
doAssert fmt"{15:08}" == "00000015" # int, works
|
||||||
|
doAssert fmt"{1.5:08}" == "000001.5" # float, works
|
||||||
|
doAssert fmt"{1.5:0>8}" == "000001.5" # workaround using fill char works for positive floats
|
||||||
|
doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative floats
|
||||||
|
doAssert fmt"{-1.5:08}" == "-00001.5" # works
|
||||||
|
doAssert fmt"{1.5:+08}" == "+00001.5" # works
|
||||||
|
doAssert fmt"{1.5: 08}" == " 00001.5" # works
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ doAssert "@[23, 45]" == $(@[23, 45])
|
||||||
doAssert "[32, 45]" == $([32, 45])
|
doAssert "[32, 45]" == $([32, 45])
|
||||||
doAssert """@["", "foo", "bar"]""" == $(@["", "foo", "bar"])
|
doAssert """@["", "foo", "bar"]""" == $(@["", "foo", "bar"])
|
||||||
doAssert """["", "foo", "bar"]""" == $(["", "foo", "bar"])
|
doAssert """["", "foo", "bar"]""" == $(["", "foo", "bar"])
|
||||||
|
doAssert """["", "foo", "bar"]""" == $(@["", "foo", "bar"].toOpenArray(0, 2))
|
||||||
|
|
||||||
# bug #2395
|
# bug #2395
|
||||||
let alphaSet: set[char] = {'a'..'c'}
|
let alphaSet: set[char] = {'a'..'c'}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ proc nimcacheDir(filename, options: string, target: TTarget): string =
|
||||||
proc callCompiler(cmdTemplate, filename, options: string,
|
proc callCompiler(cmdTemplate, filename, options: string,
|
||||||
target: TTarget, extraOptions=""): TSpec =
|
target: TTarget, extraOptions=""): TSpec =
|
||||||
let nimcache = nimcacheDir(filename, options, target)
|
let nimcache = nimcacheDir(filename, options, target)
|
||||||
let options = options & " --nimCache:" & nimcache.quoteShell & extraOptions
|
let options = options & " " & ("--nimCache:" & nimcache).quoteShell & extraOptions
|
||||||
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
||||||
"options", options, "file", filename.quoteShell,
|
"options", options, "file", filename.quoteShell,
|
||||||
"filedir", filename.getFileDir()])
|
"filedir", filename.getFileDir()])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue