diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-06-04 16:16:50 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-06-04 16:16:50 +0200 |
commit | 12996c08a1148125271a9b5f465c2ac44f261935 (patch) | |
tree | 753257142359d8c2385b06a0f2487cae9c8679fe /lib/pure | |
parent | 2e9d486378965046227517f15a311cb72a84009e (diff) | |
parent | 582786d0684b76a5bab5faa54304b2873bdcff5e (diff) | |
download | Nim-12996c08a1148125271a9b5f465c2ac44f261935.tar.gz |
fixed merge conflict
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/algorithm.nim | 43 | ||||
-rw-r--r-- | lib/pure/complex.nim | 4 | ||||
-rw-r--r-- | lib/pure/json.nim | 3 | ||||
-rw-r--r-- | lib/pure/math.nim | 206 | ||||
-rw-r--r-- | lib/pure/rationals.nim | 36 | ||||
-rw-r--r-- | lib/pure/strformat.nim | 22 | ||||
-rw-r--r-- | lib/pure/strscans.nim | 19 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 7 | ||||
-rw-r--r-- | lib/pure/times.nim | 721 |
9 files changed, 758 insertions, 303 deletions
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 98330b680..81badfae6 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -122,14 +122,14 @@ const onlySafeCode = true 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 the location where `key` would be if it were. In other - ## words if you have a sorted sequence and you call + ## Returns a position to the first element in the `a` that is greater 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, lowerBound(thing, elm)) ## 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 second version uses the default comparison function `cmp`. ## ## 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 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) = when false: a = b @@ -546,6 +576,11 @@ when isMainModule: doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 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: var s = newSeq[int]() s.fill(0) diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 98cab1a5a..ba5c571ce 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -25,6 +25,10 @@ type Complex* = tuple[re, im: float] ## 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 = ## Convert some integer ``x`` to a complex number. result.re = x diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 2bb830bcb..e7ad5bd5a 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -558,6 +558,8 @@ proc escapeJson*(s: string; result: var string) = of '\t': result.add("\\t") of '\r': result.add("\\r") of '"': result.add("\\\"") + of '\0'..'\7': result.add("\\u000" & $ord(c)) + of '\14'..'\31': result.add("\\u00" & $ord(c)) of '\\': result.add("\\\\") else: result.add(c) 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 escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\"" + doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0020\"" # for #7887 # Test with extra data when not defined(js): diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 49d87f007..6be19a339 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -130,7 +130,7 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} = for i in items(x): result = result + i {.push noSideEffect.} -when not defined(JS): +when not defined(JS): # C proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".} proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".} ## 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: float64): float64 {.importc: "log10", header: "<math.h>".} ## 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` proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".} proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".} ## 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: float64): float64 {.importc: "acos", header: "<math.h>".} ## 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 ## (`x` near 0). - 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 arcsinh*(x: float32): float32 {.importc: "asinhf", header: "<math.h>".} + proc arcsinh*(x: float64): float64 {.importc: "asinh", header: "<math.h>".} + ## 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` + +else: # JS + proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} + proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} - 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 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: float64): float64 {.importc: "hypot", header: "<math.h>".} ## Computes the hypotenuse of a right-angle triangle with `x` and ## `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: float64): float64 {.importc: "pow", header: "<math.h>".} ## computes x to power raised of y. @@ -295,57 +363,31 @@ when not defined(JS): ## .. code-block:: nim ## echo trunc(PI) # 3.0 - proc fmod*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".} - proc fmod*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".} + proc fmod*(x, y: float32): float32 {.deprecated, importc: "fmodf", header: "<math.h>".} + proc fmod*(x, y: float64): float64 {.deprecated, importc: "fmod", header: "<math.h>".} ## Computes the remainder of `x` divided by `y` ## ## .. code-block:: nim ## echo fmod(-2.5, 0.3) ## -0.1 -else: - proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} - proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} + proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".} + proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".} + ## 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: float64): float64 {.importc: "Math.floor", nodecl.} proc ceil*(x: float32): float32 {.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 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 pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} - - 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 `mod`*(x, y: float32): float32 {.importcpp: "# % #".} + proc `mod`*(x, y: float64): float64 {.importcpp: "# % #".} + ## Computes the modulo operation for float operators. proc round*[T: float32|float64](x: T, places: int = 0): T = ## 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) 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): proc c_frexp*(x: float32, exponent: var int32): float32 {. importc: "frexp", header: "<math.h>".} @@ -426,15 +483,6 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = ## `NaN`. 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.} @@ -599,3 +647,19 @@ when isMainModule: doAssert fac(2) == 2 doAssert fac(3) == 6 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 diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 7907b4e6c..3946cf85b 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -241,6 +241,33 @@ proc abs*[T](x: Rational[T]): Rational[T] = result.num = abs x.num 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 = ## Computes hash for rational `x` # 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.22) == 11 // 50 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 diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index a8b128460..12a102c9f 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -524,8 +524,26 @@ proc format*(value: SomeFloat; specifier: string; res: var string) = " of 'e', 'E', 'f', 'F', 'g', 'G' but got: " & spec.typ) var f = formatBiggestFloat(value, fmode, spec.precision) - if value >= 0.0 and spec.sign != '-': - f = spec.sign & f + var sign = false + 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: let align = if spec.align == '\0': '>' else: spec.align let result = alignString(f, spec.minimumWidth, diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index b0af149b5..11f182495 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -316,6 +316,9 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b conds.add resLen 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 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: matchBind "parseIdent" else: - error("no string var given for $w") + matchError inc i of 'b': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseBin" else: - error("no int var given for $b") + matchError inc i of 'o': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseOct" else: - error("no int var given for $o") + matchError inc i of 'i': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseInt" else: - error("no int var given for $i") + matchError inc i of 'h': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseHex" else: - error("no int var given for $h") + matchError inc i of 'f': if i < results.len and getType(results[i]).typeKind == ntyFloat: matchBind "parseFloat" else: - error("no float var given for $f") + matchError inc i of 's': 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 resLen else: - error("no string var given for $" & pattern[p]) + matchError inc i of '{': 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 resLen else: - error("no var given for $" & expr) + error("no var given for $" & expr & " (position: " & $p & ")") inc i of '[': inc p diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index ee3072c85..a4fd20fdb 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1854,6 +1854,10 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, ## ## If ``precision == -1``, it tries to format it nicely. when defined(js): + var precision = precision + if precision == -1: + # use the same default precision as c_sprintf + precision = 6 var res: cstring case format of ffDefault: @@ -1863,6 +1867,9 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, of ffScientific: {.emit: "`res` = `f`.toExponential(`precision`);".} 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: # Depending on the locale either dot or comma is produced, # but nothing else is possible: diff --git a/lib/pure/times.nim b/lib/pure/times.nim index f6567cf58..60b362665 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -35,7 +35,7 @@ # of the standard library! import - strutils, parseutils + strutils, parseutils, algorithm, math include "system/inclrtl" @@ -183,6 +183,11 @@ type ## The point in time represented by ``ZonedTime`` is ``adjTime + utcOffset.seconds``. 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, TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].} @@ -229,31 +234,23 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T = result.seconds -= 1 result.nanosecond = nanosecond.int -proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = - ## Create a ``Time`` from a unix timestamp and a nanosecond part. - result.seconds = unix - result.nanosecond = nanosecond +# 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 .} +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 = ## Get the fractional part of a ``Time`` as the number ## of nanoseconds of the second. 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.} = ## Number of whole weeks represented by the duration. @@ -306,63 +303,6 @@ proc fractional*(dur: Duration): Duration {.inline.} = doAssert dur.fractional == initDuration(nanoseconds = 5) 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.} = ## 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.} = ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``). + runnableExamples: + doAssert fromUnix(0).toUnix() == 0 + t.seconds 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. 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 .} @@ -489,6 +427,114 @@ template lqImpl(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 +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.} = ## Add two durations together. runnableExamples: @@ -535,7 +581,7 @@ proc `*`*(a: int64, b: Duration): Duration {.operator} = proc `*`*(a: Duration, b: int64): Duration {.operator} = ## Multiply a duration by some scalar. runnableExamples: - doAssert 5 * initDuration(seconds = 1) == initDuration(seconds = 5) + doAssert initDuration(seconds = 1) * 5 == initDuration(seconds = 5) b * a 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) 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".} = ## Computes the duration between two points in time. 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) 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".} = ## Subtracts a duration of time from a ``Time``. runnableExamples: doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1) 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.} = ## 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) proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} = @@ -615,23 +676,8 @@ proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = seconds.inc dt.utcOffset 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 = + ## Create a new ``DateTime`` using ``ZonedTime`` in the specified timezone. let s = zt.adjTime.seconds let epochday = (if s >= 0: s else: s - (secondsInDay - 1)) div secondsInDay var rem = s - epochday * secondsInDay @@ -917,11 +963,10 @@ proc `+`*(ti1, ti2: TimeInterval): TimeInterval = proc `-`*(ti: TimeInterval): TimeInterval = ## Reverses a time interval - ## - ## .. code-block:: nim - ## - ## let day = -initInterval(hours=24) - ## echo day # -> (milliseconds: 0, seconds: 0, minutes: 0, hours: -24, days: 0, months: 0, years: 0) + runnableExamples: + let day = -initTimeInterval(hours=24) + doAssert day.hours == -24 + result = TimeInterval( nanoseconds: -ti.nanoseconds, microseconds: -ti.microseconds, @@ -939,13 +984,10 @@ proc `-`*(ti1, ti2: TimeInterval): TimeInterval = ## Subtracts TimeInterval ``ti1`` from ``ti2``. ## ## Time components are subtracted one-by-one, see output: - ## - ## .. code-block:: nim - ## let a = fromUnix(1_000_000_000) - ## let b = fromUnix(1_500_000_000) - ## 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) + runnableExamples: + let ti1 = initTimeInterval(hours=24) + let ti2 = initTimeInterval(hours=4) + doAssert (ti1 - ti2) == initTimeInterval(hours=20) result = ti1 + (-ti2) @@ -974,6 +1016,37 @@ proc `$`*(m: Month): string = "November", "December"] 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.} = ## TimeInterval of ``nanos`` nanoseconds. initTimeInterval(nanoseconds = nanos) @@ -1067,6 +1140,37 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): tuple[adjDur, absDu minutes = interval.minutes, 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 = ## Adds ``interval`` to ``dt``. Components from ``interval`` are added ## 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 ## 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. + runnableExamples: + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + doAssert $(dt - 5.days) == "2017-03-25T00:00:00+00:00" + dt + (-interval) 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) 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) +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 = interval.years == 0 and interval.months == 0 and interval.days == 0 and interval.weeks == 0 @@ -1121,12 +1262,116 @@ proc evaluateStaticInterval(interval: TimeInterval): Duration = minutes = interval.minutes, 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 = ## Adds `interval` to `time`. ## If `interval` contains any years, months, weeks or days the operation ## is performed in the local timezone. - ## - ## ``echo getTime() + 1.day`` + runnableExamples: + let tm = fromUnix(0) + doAssert tm + 5.seconds == fromUnix(5) + if interval.isStaticInterval: time + evaluateStaticInterval(interval) else: @@ -1136,14 +1381,21 @@ proc `+=`*(time: var Time, interval: TimeInterval) = ## Modifies `time` by adding `interval`. ## If `interval` contains any years, months, weeks or days the operation ## is performed in the local timezone. + runnableExamples: + var tm = fromUnix(0) + tm += 5.seconds + doAssert tm == fromUnix(5) + time = time + interval proc `-`*(time: Time, interval: TimeInterval): Time = ## Subtracts `interval` from Time `time`. ## If `interval` contains any years, months, weeks or days the operation ## is performed in the local timezone. - ## - ## ``echo getTime() - 1.day`` + runnableExamples: + let tm = fromUnix(5) + doAssert tm - 5.seconds == fromUnix(0) + if interval.isStaticInterval: time - evaluateStaticInterval(interval) else: @@ -1153,6 +1405,10 @@ proc `-=`*(time: var Time, interval: TimeInterval) = ## Modifies `time` by subtracting `interval`. ## If `interval` contains any years, months, weeks or days the operation ## is performed in the local timezone. + runnableExamples: + var tm = fromUnix(5) + tm -= 5.seconds + doAssert tm == fromUnix(0) time = time - interval proc formatToken(dt: DateTime, token: string, buf: var string) = @@ -1274,6 +1530,12 @@ proc formatToken(dt: DateTime, token: string, buf: var string) = buf.add(':') if minutes < 10: buf.add('0') 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 "": discard else: @@ -1284,40 +1546,46 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}= ## This procedure formats `dt` as specified by `f`. The following format ## specifiers are available: ## - ## ========== ================================================================================= ================================================ - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## MMMM Full month string, properly capitalized. ``September -> September`` - ## 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`` - ## 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. - ## 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`` - ## yyyy Displays the year to four digits. ``2012 -> 2012`` - ## 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`` - ## zzz Same as above but with ``:mm`` where *mm* represents minutes. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00`` - ## ========== ================================================================================= ================================================ + ## ============ ================================================================================= ================================================ + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## MMMM Full month string, properly capitalized. ``September -> September`` + ## 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`` + ## 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. + ## 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`` + ## yyyy Displays the year to four digits. ``2012 -> 2012`` + ## 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`` + ## 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 ## ``hh'->'mm`` will give ``01->56``. The following characters can be ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]`` ## ``,``. However you don't need to necessarily separate format specifiers, a ## 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 = "" var i = 0 @@ -1348,9 +1616,25 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}= inc(i) 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.} = ## Converts a `DateTime` object to a string representation. ## 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: result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") # todo: optimize this 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.} = ## 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``. + 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 {.pop.} @@ -1574,6 +1862,11 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) = j += 4 dt.utcOffset += factor * value[j..j+1].parseInt() * 60 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: # Ignore the token and move forward in the value string by the same length 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 ## already, so no timezone conversion will be done in that case. ## - ## ========== ================================================================================= ================================================ - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## 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`` - ## MMMM Full month string, properly capitalized. ``September -> September`` - ## 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`` - ## 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. - ## yy Displays the year to two digits. ``2012 -> 12`` - ## 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`` - ## 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`` - ## ========== ================================================================================= ================================================ + ## ======================= ================================================================================= ================================================ + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## 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`` + ## MMMM Full month string, properly capitalized. ``September -> September`` + ## 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`` + ## 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. + ## yy Displays the year to two digits. ``2012 -> 12`` + ## 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`` + ## 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`` + ## fff/ffffff/fffffffff for consistency with format - nanoseconds ``1 -> 1 nanosecond`` + ## ======================= ================================================================================= ================================================ ## ## Other strings can be inserted by putting them in ``''``. For example ## ``hh'->'mm`` will give ``01->56``. The following characters can be ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]`` ## ``,``. However you don't need to necessarily separate format specifiers, a ## 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 j = 0 # pointer for value string var token = "" @@ -1667,6 +1965,13 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime = # Otherwise convert to `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 = ## 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. ## ## To be used when diffing times. - ## - ## .. code-block:: nim - ## let a = fromSeconds(1_000_000_000) - ## let b = fromSeconds(1_500_000_000) - ## echo a, " ", b # real dates - ## echo a.toTimeInterval # meaningless value, don't use it by itself - ## 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) + runnableExamples: + let a = fromUnix(10) + let dt = initDateTime(01, mJan, 1970, 00, 00, 00, local()) + doAssert a.toTimeInterval() == initTimeInterval( + years=1970, days=1, seconds=10, hours=convert( + Seconds, Hours, -dt.utcOffset + ) + ) + var dt = time.local initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour, 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): type Clock {.importc: "clock_t".} = distinct int @@ -1747,11 +2030,14 @@ when not defined(JS): ## The value of the result has no meaning. ## To generate useful timing values, take the difference between ## the results of two ``cpuTime`` calls: - ## - ## .. code-block:: nim - ## var t0 = cpuTime() - ## doWork() - ## echo "CPU time [s] ", cpuTime() - t0 + runnableExamples: + var t0 = cpuTime() + # some useless work here (calculate fibonacci) + var fib = @[0, 1, 1] + 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) 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.} = ## Converts a broken-down time structure to calendar time representation. ## - ## **Warning:** This procedure is deprecated since version 0.14.0. - ## Use ``toTime`` instead. + ## **Deprecated since v0.14.0:** use ``toTime`` instead. dt.toTime when defined(JS): var start = getTime() proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} = - ## get the milliseconds from the start of the program. **Deprecated since - ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead. + ## get the milliseconds from the start of the program. + ## **Deprecated since v0.8.10:** use ``epochTime`` or ``cpuTime`` instead. let dur = getTime() - start result = (convert(Seconds, Milliseconds, dur.seconds) + convert(Nanoseconds, Milliseconds, dur.nanosecond)).int @@ -1875,19 +2160,19 @@ else: proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} = ## Converts a Time to a TimeInterval. ## - ## **Warning:** This procedure is deprecated since version 0.14.0. - ## Use ``toTimeInterval`` instead. + ## **Deprecated since v0.14.0:** use ``toTimeInterval`` instead. # Milliseconds not available from Time t.toTimeInterval() 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) proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} = ## Returns the day of the week enum from day, month and year, ## 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. let a = (14 - month) div 12 |