1 import Base 2 import ./date.bend as D 3 import ./duration.bend as Dur 4 5 type Instant.Error is Data: 6 OutOfRange{} 7 8 type Instant is Data: 9 Instant{days: U32, sod: U32, nanos: U32} 10 11 def Instant.epoch_days() -> U32: 12 719468 13 14 def 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 20 def 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 29 def 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 34 def 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 43 def 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 48 def 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 55 def Instant.from_utc_date(d: D.Date) -> Instant: 56 Instant{D.Date.to_days(d), 0, 0} 57 58 def 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 63 def 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 71 def 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 78 def 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 87 def 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 92 def Instant.is_gt(a: Instant, b: Instant) -> Bool: 93 Instant.is_lt(b, a) 94 95 def Instant.is_le(a: Instant, b: Instant) -> Bool: 96 Bool.not(Instant.is_lt(b, a)) 97 98 def Instant.is_ge(a: Instant, b: Instant) -> Bool: 99 Bool.not(Instant.is_lt(a, b)) 100 101 def 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 110 def 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 119 def 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 127 def 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 136 def Instant.as_dur(i: Instant) -> Dur.Duration: 137 match i: 138 case Instant{days, sod, nanos}: 139 Dur.Duration{days, sod, nanos} 140 141 def 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 146 def 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 151 def 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 160 def 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 171 def 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 176 def Instant.trunc_sec(i: Instant) -> Instant: 177 match i: 178 case Instant{days, sod, _}: 179 Instant{days, sod, 0} 180 181 def 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 186 def 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 191 def Instant.trunc_day(i: Instant) -> Instant: 192 match i: 193 case Instant{days, _, _}: 194 Instant{days, 0, 0}