+32
-23
src/birl/duration.gleam
+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
+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
+
}