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}