datetime handling for gleam

fix unmatched assert on blur of round value

Changed files
+63 -23
src
test
+32 -23
src/birl/duration.gleam
··· 204 204 /// - `blur_to(days(16), Month)` -> `0` 205 205 /// - `blur_to(days(20), Month)` -> `1` 206 206 pub fn blur_to(duration: Duration, unit: Unit) -> Int { 207 - let assert Ok(unit_value) = list.key_find(unit_values, unit) 207 + let unit_value = unit_values(unit) 208 208 let Duration(value) = duration 209 209 let #(unit_counts, remaining) = extract(value, unit_value) 210 210 case remaining >= unit_value * 2 / 3 { ··· 215 215 216 216 /// approximates the duration by a value in a single unit 217 217 pub fn blur(duration: Duration) -> #(Int, Unit) { 218 - case decompose(duration) { 219 - [] -> #(0, MicroSecond) 220 - decomposed -> 221 - decomposed 222 - |> list.reverse 223 - |> inner_blur 224 - } 218 + decompose(duration) 219 + |> list.reverse 220 + |> inner_blur 225 221 } 226 222 227 223 const milli_second = 1000 ··· 244 240 245 241 const accurate_year = 31_556_952_000_000 246 242 247 - const unit_values = [ 248 - #(Year, year), #(Month, month), #(Week, week), #(Day, day), #(Hour, hour), 249 - #(Minute, minute), #(Second, second), #(MilliSecond, milli_second), 250 - #(MicroSecond, 1), 251 - ] 243 + fn unit_values(unit: Unit) { 244 + case unit { 245 + Year -> year 246 + Month -> month 247 + Week -> week 248 + Day -> day 249 + Hour -> hour 250 + Minute -> minute 251 + Second -> second 252 + MilliSecond -> milli_second 253 + MicroSecond -> 1 254 + } 255 + } 252 256 253 257 fn inner_blur(values: List(#(Int, Unit))) -> #(Int, Unit) { 254 - let assert [second, leading, ..] = values 255 - let assert Ok(leading_unit) = list.key_find(unit_values, leading.1) 256 - let assert Ok(second_unit) = list.key_find(unit_values, second.1) 258 + case values { 259 + [] -> #(0, MicroSecond) 260 + [single] -> single 261 + [smaller, larger, ..rest] -> { 262 + let smaller_unit_value = unit_values(smaller.1) 263 + let larger_unit_value = unit_values(larger.1) 264 + 265 + let at_least_two_thirds = 266 + smaller.0 * smaller_unit_value < { larger_unit_value * 2 / 3 } 257 267 258 - let leading = case second.0 * second_unit < { leading_unit * 2 / 3 } { 259 - True -> leading 260 - False -> #(leading.0 + 1, leading.1) 261 - } 268 + let rounded = case at_least_two_thirds { 269 + True -> larger 270 + False -> #(larger.0 + 1, larger.1) 271 + } 262 272 263 - case list.drop(values, 2) { 264 - [] -> leading 265 - chopped -> inner_blur([leading, ..chopped]) 273 + inner_blur([rounded, ..rest]) 274 + } 266 275 } 267 276 } 268 277
+31
test/birl_test.gleam
··· 27 27 gleeunit.main() 28 28 } 29 29 30 + // `birl` tests 31 + 30 32 pub fn now_test() { 31 33 birl.now() 32 34 |> birl.to_iso8601 ··· 241 243 birl.weekday_to_short_string(birl.Mon) 242 244 |> should.equal("Mon") 243 245 } 246 + 247 + // `duration` tests 248 + 249 + pub fn blur_test() { 250 + // unchanged 251 + duration.seconds(59) 252 + |> duration.blur 253 + |> should.equal(#(59, duration.Second)) 254 + 255 + // exact value 256 + duration.seconds(60) 257 + |> duration.blur 258 + |> should.equal(#(1, duration.Minute)) 259 + 260 + // almost rounded 261 + duration.seconds(99) 262 + |> duration.blur 263 + |> should.equal(#(1, duration.Minute)) 264 + 265 + // rounded 266 + duration.seconds(100) 267 + |> duration.blur 268 + |> should.equal(#(2, duration.Minute)) 269 + 270 + // goes through many units 271 + duration.seconds(60 * 60 * 24 * 400) 272 + |> duration.blur 273 + |> should.equal(#(1, duration.Year)) 274 + }