diff --git a/docs/Datetime.html b/docs/Datetime.html index 3824225..e8fd667 100644 --- a/docs/Datetime.html +++ b/docs/Datetime.html @@ -1200,6 +1200,29 @@

+
+ +

+ subsecond-nanos +

+
+
+ defn +
+

+ (Fn [Uint64] Int) +

+
+                        (subsecond-nanos t)
+                    
+

+

returns the sub-second part of the nanosecond count t, +that is, t modulo one billion.

+

The reduction is exact over the whole Uint64 range, including counts wider +than a C long.

+ +

+

diff --git a/test/time.carp b/test/time.carp index b176ba5..1964a50 100644 --- a/test/time.carp +++ b/test/time.carp @@ -17,6 +17,11 @@ ; render a Datetime as "YYYY-MM-DD HH:MM:SS" for whole-instant comparisons. (defn stamp [dt] (fmt "%s %s" &(Datetime.isoformat dt) &(Datetime.isotime dt))) +; parts stay under 2^31: a wider Long literal truncates where C long is 32 bits. +(defn nanos [secs ns] + (let [billion (Uint64.from-long 1000000000l)] + (+ (* (Uint64.from-long secs) billion) (Uint64.from-long ns)))) + ; n UTF-8 continuation bytes, which decode to no character at all. (defn conts [n] (String.from-bytes &(Array.replicate n &128b))) @@ -669,6 +674,47 @@ &(at-tz 2100 1 1 19 0 0 @&Timezone.utc)) "equal-instant? stays timezone-aware past 2038") + ; --- sub-second reduction of a 64-bit clock --- + (assert-equal test + 999999999 + (Datetime.subsecond-nanos (Uint64.from-long 999999999l)) + "subsecond-nanos leaves a count below one second alone") + (assert-equal test + 500000000 + (Datetime.subsecond-nanos (nanos 1l 500000000l)) + "subsecond-nanos drops whole seconds") + (assert-equal test + 294967296 + (Datetime.subsecond-nanos + (Uint64.bit-shift-left (Uint64.from-long 1l) (Uint64.from-long 32l))) + "subsecond-nanos reduces 2^32") + (assert-equal test + 662882507 + (Datetime.subsecond-nanos (nanos 1787138980l 662882507l)) + "subsecond-nanos reduces a realistic monotonic-clock reading") + (assert-equal test + 854775808 + (Datetime.subsecond-nanos + (Uint64.bit-shift-left (Uint64.from-long 1l) (Uint64.from-long 63l))) + "subsecond-nanos reduces 2^63") + (assert-equal test + 709551615 + (Datetime.subsecond-nanos Uint64.MAX) + "subsecond-nanos reduces the largest representable count") + + ; with no second boundary between the samples, now's nanos sit between them. + (let-do [billion (Uint64.from-long 1000000000l) + a (System.nanotime) + dt (Datetime.now) + b (System.nanotime) + lo (Datetime.subsecond-nanos a) + hi (Datetime.subsecond-nanos b) + ns (Maybe.from @(Datetime.nanoseconds &dt) -1) + spans-a-second? (or (> (- b a) billion) (> lo hi))] + (assert-true test + (or spans-a-second? (and (<= lo ns) (<= ns hi))) + "now reads its nanoseconds off the full-width clock")) + (assert-equal test &@"00:00:30" &(Datetime.isotime diff --git a/time.carp b/time.carp index e189aa9..d01f965 100644 --- a/time.carp +++ b/time.carp @@ -459,6 +459,15 @@ The ISO format is of the form `HH:MM:SS`. The date value is not represented.") (Maybe.from @(minutes dt) 0) (Maybe.from @(seconds dt) 0))) + (doc subsecond-nanos "returns the sub-second part of the nanosecond count `t`, +that is, `t` modulo one billion. + +The reduction is exact over the whole `Uint64` range, including counts wider +than a C `long`.") + (defn subsecond-nanos [t] + (let [billion (Uint64.from-long 1000000000l)] + (Long.to-int (Uint64.to-long (- t (* (/ t billion) billion)))))) + (doc now "returns the `Datetime` representing the current time. All of the time information is obtained from the operating system directly.") @@ -471,7 +480,7 @@ All of the time information is obtained from the operating system directly.") (Maybe.Just @(TM.tm_hour ct)) (Maybe.Just @(TM.tm_min ct)) (Maybe.Just @(TM.tm_sec ct)) - (Maybe.Just (Long.to-int (mod (Uint64.to-long t) 1000000000l))) + (Maybe.Just (subsecond-nanos t)) (Maybe.Just (Timezone.init @(TM.tm_zone ct) @(TM.tm_gmtoff ct)