instant.bend
bend-datetime@0.4.0.0 · 194 lines · 0 definitions
1import Base
2import bend-datetime@0.4.0.0/date.bend as D
3import bend-datetime@0.4.0.0/duration.bend as Dur
4
5type Instant.Error is Data:
6 OutOfRange{}
7
8type Instant is Data:
9 Instant{days: U32, sod: U32, nanos: U32}
10
11def Instant.epoch_days() -> U32:
12 719468
13
14def Instant.unix_fit(+udays: U32, +sod: U32) -> Bool:
15 Bool.or(
16 U32.is_lt(udays, 49710),
17 Bool.and(U32.is_eq(udays, 49710), U32.is_le(sod, 23295))
18 )
19
20def Instant.to_unix.add(
21 +udays: U32, +sod: U32, ok: Bool
22) -> Result<&2, &2, Instant.Error, U32>:
23 match ok:
24 case False{}:
25 Fail{OutOfRange{}}
26 case True{}:
27 Done{U32.add(U32.mul(udays, 86400), sod)}
28
29def Instant.to_unix.d(
30 +udays: U32, +sod: U32
31) -> Result<&2, &2, Instant.Error, U32>:
32 Instant.to_unix.add(udays, sod, Instant.unix_fit(udays, sod))
33
34def Instant.to_unix.ge(
35 +days: U32, +sod: U32, ok: Bool
36) -> Result<&2, &2, Instant.Error, U32>:
37 match ok:
38 case False{}:
39 Fail{OutOfRange{}}
40 case True{}:
41 Instant.to_unix.d(U32.sub(days, Instant.epoch_days()), sod)
42
43def Instant.to_unix(i: Instant) -> Result<&2, &2, Instant.Error, U32>:
44 match i:
45 case Instant{+days, +sod, _}:
46 Instant.to_unix.ge(days, sod, U32.is_ge(days, Instant.epoch_days()))
47
48def Instant.from_unix(+secs: U32) -> Instant:
49 Instant{
50 U32.add(U32.div(secs, 86400), Instant.epoch_days()),
51 U32.mod(secs, 86400),
52 0
53 }
54
55def Instant.from_utc_date(d: D.Date) -> Instant:
56 Instant{D.Date.to_days(d), 0, 0}
57
58def Instant.to_utc_date(i: Instant) -> Result<&2, &2, D.Date.Error, D.Date>:
59 match i:
60 case Instant{days, _, _}:
61 D.Date.from_days(days)
62
63def Instant.is_eq(a: Instant, b: Instant) -> Bool:
64 match a b:
65 case Instant{+d1, +s1, +n1} Instant{+d2, +s2, +n2}:
66 Bool.and(
67 U32.is_eq(d1, d2),
68 Bool.and(U32.is_eq(s1, s2), U32.is_eq(n1, n2))
69 )
70
71def Instant.is_lt.n(+n1: U32, +n2: U32, eq_s: Bool, slt: Bool) -> Bool:
72 match eq_s:
73 case False{}:
74 slt
75 case True{}:
76 U32.is_lt(n1, n2)
77
78def Instant.is_lt.s(
79 +s1: U32, +n1: U32, +s2: U32, +n2: U32, eq_d: Bool, dlt: Bool
80) -> Bool:
81 match eq_d:
82 case False{}:
83 dlt
84 case True{}:
85 Instant.is_lt.n(n1, n2, U32.is_eq(s1, s2), U32.is_lt(s1, s2))
86
87def Instant.is_lt(a: Instant, b: Instant) -> Bool:
88 match a b:
89 case Instant{+d1, +s1, +n1} Instant{+d2, +s2, +n2}:
90 Instant.is_lt.s(s1, n1, s2, n2, U32.is_eq(d1, d2), U32.is_lt(d1, d2))
91
92def Instant.is_gt(a: Instant, b: Instant) -> Bool:
93 Instant.is_lt(b, a)
94
95def Instant.is_le(a: Instant, b: Instant) -> Bool:
96 Bool.not(Instant.is_lt(b, a))
97
98def Instant.is_ge(a: Instant, b: Instant) -> Bool:
99 Bool.not(Instant.is_lt(a, b))
100
101def Instant.from.date(
102 +days: U32, +sod: U32, +nanos: U32, r: Result<&2, &2, D.Date.Error, D.Date>
103) -> Result<&2, &2, Instant.Error, Instant>:
104 match r:
105 case Fail{_}:
106 Fail{OutOfRange{}}
107 case Done{_}:
108 Done{Instant{days, sod, nanos}}
109
110def Instant.from.rng(
111 +days: U32, +sod: U32, +nanos: U32, ok: Bool
112) -> Result<&2, &2, Instant.Error, Instant>:
113 match ok:
114 case False{}:
115 Fail{OutOfRange{}}
116 case True{}:
117 Instant.from.date(days, sod, nanos, D.Date.from_days(days))
118
119def Instant.from(
120 +days: U32, +sod: U32, +nanos: U32
121) -> Result<&2, &2, Instant.Error, Instant>:
122 Instant.from.rng(
123 days, sod, nanos,
124 Bool.and(U32.is_le(sod, 86399), U32.is_le(nanos, 999999999))
125 )
126
127def Instant.of_dur.map(
128 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>
129) -> Result<&2, &2, Instant.Error, Instant>:
130 match r:
131 case Fail{_}:
132 Fail{OutOfRange{}}
133 case Done{Dur.Duration{days, sod, nanos}}:
134 Instant.from(days, sod, nanos)
135
136def Instant.as_dur(i: Instant) -> Dur.Duration:
137 match i:
138 case Instant{days, sod, nanos}:
139 Dur.Duration{days, sod, nanos}
140
141def Instant.add(
142 i: Instant, d: Dur.Duration
143) -> Result<&2, &2, Instant.Error, Instant>:
144 Instant.of_dur.map(Dur.Duration.add(Instant.as_dur(i), d))
145
146def Instant.sub(
147 i: Instant, d: Dur.Duration
148) -> Result<&2, &2, Instant.Error, Instant>:
149 Instant.of_dur.map(Dur.Duration.sub(Instant.as_dur(i), d))
150
151def Instant.until.map(
152 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>
153) -> Result<&2, &2, Instant.Error, Dur.Duration>:
154 match r:
155 case Fail{_}:
156 Fail{OutOfRange{}}
157 case Done{d}:
158 Done{d}
159
160def Instant.until.ord(
161 start: Instant, end: Instant, lt: Bool
162) -> Result<&2, &2, Instant.Error, Dur.Duration>:
163 match lt:
164 case True{}:
165 Fail{OutOfRange{}}
166 case False{}:
167 Instant.until.map(
168 Dur.Duration.sub(Instant.as_dur(end), Instant.as_dur(start))
169 )
170
171def Instant.until(
172 +start: Instant, +end: Instant
173) -> Result<&2, &2, Instant.Error, Dur.Duration>:
174 Instant.until.ord(start, end, Instant.is_lt(end, start))
175
176def Instant.trunc_sec(i: Instant) -> Instant:
177 match i:
178 case Instant{days, sod, _}:
179 Instant{days, sod, 0}
180
181def Instant.trunc_min(i: Instant) -> Instant:
182 match i:
183 case Instant{days, +sod, _}:
184 Instant{days, U32.sub(sod, U32.mod(sod, 60)), 0}
185
186def Instant.trunc_hour(i: Instant) -> Instant:
187 match i:
188 case Instant{days, +sod, _}:
189 Instant{days, U32.sub(sod, U32.mod(sod, 3600)), 0}
190
191def Instant.trunc_day(i: Instant) -> Instant:
192 match i:
193 case Instant{days, _, _}:
194 Instant{days, 0, 0}