Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/Datetime.html
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ <h3 id="diff">
defn
</div>
<p class="sig">
(Fn [(Ref Datetime a), (Ref Datetime b)] Int)
(Fn [(Ref Datetime a), (Ref Datetime b)] Long)
</p>
<pre class="args">
(diff a b)
Expand Down
35 changes: 31 additions & 4 deletions docs/Duration.html
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ <h3 id="add">
</pre>
<p class="doc">
<p>adds a <code>Duration</code> <code>delta</code> to a <code>Datetime</code> <code>dt</code>.</p>
<p>A <code>Duration</code> can name a span far wider than the range of dates a <code>Datetime</code> can
represent. A result that would fall outside that range saturates at the first
or last representable date rather than wrapping.</p>

</p>
</div>
Expand Down Expand Up @@ -217,6 +220,29 @@ <h3 id="delete">

</p>
</div>
<div class="binder">
<a class="anchor" href="#from-seconds">
<h3 id="from-seconds">
from-seconds
</h3>
</a>
<div class="description">
defn
</div>
<p class="sig">
(Fn [Long] Duration)
</p>
<pre class="args">
(from-seconds n)
</pre>
<p class="doc">
<p>creates a delta from a raw second count <code>n</code>.</p>
<p>The unit constructors above take an <code>Int</code> count, which cannot name a delta
longer than about 68 years in seconds. This is the counterpart to
<a href="#to-seconds"><code>to-seconds</code></a>, so a delta of any width round-trips through it.</p>

</p>
</div>
<div class="binder">
<a class="anchor" href="#hours">
<h3 id="hours">
Expand Down Expand Up @@ -477,6 +503,7 @@ <h3 id="sub">
</pre>
<p class="doc">
<p>subtracts a <code>Duration</code> <code>delta</code> from a <code>Datetime</code> <code>dt</code>.</p>
<p>Out-of-range results saturate, as in <a href="#add"><code>add</code></a>.</p>

</p>
</div>
Expand All @@ -490,7 +517,7 @@ <h3 id="to-days">
defn
</div>
<p class="sig">
(Fn [(Ref Duration a)] Int)
(Fn [(Ref Duration a)] Long)
</p>
<pre class="args">
(to-days d)
Expand All @@ -511,7 +538,7 @@ <h3 id="to-hours">
defn
</div>
<p class="sig">
(Fn [(Ref Duration a)] Int)
(Fn [(Ref Duration a)] Long)
</p>
<pre class="args">
(to-hours d)
Expand All @@ -532,7 +559,7 @@ <h3 id="to-minutes">
defn
</div>
<p class="sig">
(Fn [(Ref Duration a)] Int)
(Fn [(Ref Duration a)] Long)
</p>
<pre class="args">
(to-minutes d)
Expand All @@ -553,7 +580,7 @@ <h3 id="to-seconds">
defn
</div>
<p class="sig">
(Fn [(Ref Duration a)] Int)
(Fn [(Ref Duration a)] Long)
</p>
<pre class="args">
(to-seconds d)
Expand Down
145 changes: 130 additions & 15 deletions test/time.carp
Original file line number Diff line number Diff line change
Expand Up @@ -1692,19 +1692,19 @@
"subtract 3661 seconds (1h1m1s) from 00:00:00")

(assert-equal test
0
0l
(Datetime.diff &(Datetime.date 2024 3 15) &(Datetime.date 2024 3 15))
"diff: same date is 0")
(assert-equal test
86400
86400l
(Datetime.diff &(Datetime.date 2024 3 16) &(Datetime.date 2024 3 15))
"diff: one day apart is 86400")
(assert-equal test
-86400
-86400l
(Datetime.diff &(Datetime.date 2024 3 15) &(Datetime.date 2024 3 16))
"diff: reversed order is negative")
(assert-equal test
3600
3600l
(Datetime.diff
&(Datetime.init 2024
3
Expand All @@ -1724,7 +1724,7 @@
(Maybe.Nothing)))
"diff: one hour apart is 3600")
(assert-equal test
90061
90061l
(Datetime.diff
&(Datetime.init 2024
3
Expand All @@ -1744,13 +1744,21 @@
(Maybe.Nothing)))
"diff: 1 day 1 hour 1 minute 1 second = 90061")
(assert-equal test
(* 365 86400)
(* 365l 86400l)
(Datetime.diff &(Datetime.date 2023 1 1) &(Datetime.date 2022 1 1))
"diff: non-leap year is 365 days")
(assert-equal test
(* 366 86400)
(* 366l 86400l)
(Datetime.diff &(Datetime.date 2025 1 1) &(Datetime.date 2024 1 1))
"diff: leap year 2024 has 366 days")
(assert-equal test
(* 36525l 86400l)
(Datetime.diff &(Datetime.date 2100 1 1) &(Datetime.date 2000 1 1))
"diff: a century of seconds does not wrap")
(assert-equal test
(* -36525l 86400l)
(Datetime.diff &(Datetime.date 2000 1 1) &(Datetime.date 2100 1 1))
"diff: a negative century of seconds does not wrap")

(assert-equal test
&(Datetime.date 2024 2 15)
Expand Down Expand Up @@ -1900,33 +1908,51 @@
"between: sub-day difference in seconds")

(assert-equal test
3600
3600l
(Duration.to-seconds &(Duration.hours 1))
"to-seconds: exact")
(assert-equal test
1
1l
(Duration.to-minutes &(Duration.seconds 90))
"to-minutes: truncates positive remainder")
(assert-equal test
0
0l
(Duration.to-minutes &(Duration.seconds 59))
"to-minutes: below one minute is zero")
(assert-equal test
-1
-1l
(Duration.to-minutes &(Duration.seconds -90))
"to-minutes: truncates toward zero for negatives")
(assert-equal test
1
1l
(Duration.to-hours &(Duration.minutes 90))
"to-hours: truncates remainder")
(assert-equal test
1
1l
(Duration.to-days &(Duration.hours 25))
"to-days: truncates remainder")
(assert-equal test
7
7l
(Duration.to-days &(Duration.weeks 1))
"to-days: one week is seven days")
(assert-equal test
(* 3551l 604800l)
(Duration.to-seconds &(Duration.weeks 3551))
"weeks: a count past the 32-bit second range does not wrap")
(assert-equal test
(* 24856l 86400l)
(Duration.to-seconds &(Duration.days 24856))
"days: a count past the 32-bit second range does not wrap")
(assert-equal test
(* 36525l 86400l)
(Duration.to-seconds
&(Duration.between &(Datetime.date 2100 1 1) &(Datetime.date 2000 1 1)))
"between: a century does not wrap")
(assert-equal test
36525l
(Duration.to-days
&(Duration.between &(Datetime.date 2100 1 1) &(Datetime.date 2000 1 1)))
"to-days: a century is 36525 days")

(assert-equal test
&(Duration.seconds 90)
Expand Down Expand Up @@ -1964,6 +1990,9 @@
(assert-true test
(Duration.= &(Duration.minutes 1) &(Duration.seconds 60))
"=: equal durations from different units")
(assert-false test
(Duration.= &(Duration.days 49710) &(Duration.seconds -23296))
"=: deltas that collide when truncated to 32 bits are not equal")
(assert-false test
(Duration.= &(Duration.minutes 1) &(Duration.seconds 61))
"=: unequal durations")
Expand All @@ -1979,12 +2008,28 @@
(assert-false test
(Duration.> &(Duration.seconds 30) &(Duration.minutes 1))
">: shorter is not greater")
(assert-true test
(Duration.> &(Duration.days 30000) &(Duration.days 1))
">: a delta past the 32-bit second range is still the longer one")
(assert-false test
(Duration.< &(Duration.days 30000) &(Duration.days 1))
"<: a delta past the 32-bit second range is not the shorter one")
(assert-true test
(Duration.zero? &(Duration.seconds 0))
"zero?: the zero delta")
(assert-false test
(Duration.zero? &(Duration.seconds 1))
"zero?: a non-zero delta")
(assert-false test
(Duration.zero?
&(Duration.plus &(Duration.days 49710) &(Duration.seconds 23296)))
"zero?: a delta of exactly 2^32 seconds is not the zero delta")
(assert-true test
(Duration.pos? &(Duration.days 30000))
"pos?: a delta past the 32-bit second range is positive")
(assert-false test
(Duration.neg? &(Duration.days 30000))
"neg?: a delta past the 32-bit second range is not negative")
(assert-true test (Duration.pos? &(Duration.seconds 1)) "pos?: positive delta")
(assert-false test
(Duration.pos? &(Duration.seconds -1))
Expand Down Expand Up @@ -2034,4 +2079,74 @@
(assert-equal test
&@"-1d 2h 3m 4s"
&(Duration.str &(Duration.seconds -93784))
"str: negative multi-unit"))
"str: negative multi-unit")
(assert-equal test
&@"36525d 1h 1m 1s"
&(Duration.str
&(Duration.plus &(Duration.days 36525) &(Duration.seconds 3661)))
"str: multi-decade delta")
(assert-equal test
&@"-36525d"
&(Duration.str &(Duration.negate &(Duration.days 36525)))
"str: negative multi-decade delta")

(assert-equal test
&@"2100-01-01"
&(Datetime.isoformat
&(Duration.add &(Datetime.date 2000 1 1) &(Duration.days 36525)))
"add: a century-long delta lands on the right date")
(assert-equal test
&@"2000-01-01"
&(Datetime.isoformat
&(Duration.sub &(Datetime.date 2100 1 1) &(Duration.days 36525)))
"sub: a century-long delta lands on the right date")
(assert-equal test
&@"2124-03-16 13:30:45"
&(Datetime.strftime
&(Duration.add
&(Datetime.init 2024
3
15
(Maybe.Just 12)
(Maybe.Just 30)
(Maybe.Just 45)
(Maybe.Nothing)
(Maybe.Nothing))
&(Duration.plus &(Duration.days 36525) &(Duration.hours 1)))
"%Y-%m-%d %H:%M:%S")
"add: a century-long delta keeps the time of day")

(assert-equal test
&@"0001-01-01"
&(Datetime.isoformat
&(Duration.sub &(Datetime.date 2024 1 1) &(Duration.days 739000)))
"sub: a delta reaching before the first ordinal saturates")
(assert-equal test
&@"5879611-07-11"
&(Datetime.isoformat
&(Duration.add &(Datetime.date 2024 1 1) &(Duration.days 2147483647)))
"add: a delta past the last ordinal saturates")
(assert-equal test
&@"5879611-07-11"
&(Datetime.isoformat
&(Duration.add
&(Datetime.init 2024
1
1
(Maybe.Just 23)
(Maybe.Just 0)
(Maybe.Just 0)
(Maybe.Nothing)
(Maybe.Nothing))
&(Duration.plus &(Duration.days 2147483647) &(Duration.hours 23))))
"add: saturation leaves room for the time-of-day carry")

(assert-equal test
(* 36525l 86400l)
(Duration.to-seconds &(Duration.from-seconds (* 36525l 86400l)))
"from-seconds: holds a count wider than an Int")
(assert-true test
(Duration.=
&(Duration.from-seconds (Duration.to-seconds &(Duration.days 36525)))
&(Duration.days 36525))
"from-seconds: round-trips to-seconds"))
Loading