Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/pkg.generated.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ pub fn Duration::days(Int64) -> Self
pub fn Duration::divide(Self, Int64) -> Self raise TempoError
pub fn Duration::format_iso(Self) -> String
pub fn Duration::hours(Int64) -> Self
pub fn Duration::humanize(Self) -> String
pub fn Duration::is_negative(Self) -> Bool
pub fn Duration::is_positive(Self) -> Bool
pub fn Duration::is_zero(Self) -> Bool
Expand Down
50 changes: 50 additions & 0 deletions src/tempo.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -2492,6 +2492,56 @@ pub fn Duration::format_iso(self : Duration) -> String {
}
}

///|
/// Format this duration as English elapsed time using day/hour/minute/second
/// units. Sub-second remainder is dropped.
pub fn Duration::humanize(self : Duration) -> String {
let total_seconds = self.abs().as_seconds()
if total_seconds == 0L {
"0 seconds"
} else {
let days = total_seconds / 86_400L
let rem = total_seconds - days * 86_400L
let hours = rem / 3_600L
let rem = rem - hours * 3_600L
let minutes = rem / 60L
let seconds = rem - minutes * 60L
let buf = StringBuilder()
if self.is_negative() {
buf.write_string("-")
}
let wrote = write_humanized_duration_component(buf, false, days, "day")
let wrote = write_humanized_duration_component(buf, wrote, hours, "hour")
let wrote = write_humanized_duration_component(
buf, wrote, minutes, "minute",
)
let _ = write_humanized_duration_component(buf, wrote, seconds, "second")
buf.to_string()
}
}

///|
fn write_humanized_duration_component(
buf : StringBuilder,
wrote : Bool,
value : Int64,
unit : String,
) -> Bool {
if value == 0L {
wrote
} else {
if wrote {
buf.write_string(" ")
}
buf.write_string("\{value} ")
buf.write_string(unit)
if value != 1L {
buf.write_string("s")
}
true
}
}

///|
fn[T] json_decode_error(
path : @json.JsonPath,
Expand Down
24 changes: 24 additions & 0 deletions src/tempo_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,30 @@ test "Duration::format_iso canonical components" {
assert_eq(@tempo.Duration::hours(-1L).format_iso(), "-PT1H")
}

///|
test "Duration::humanize formats elapsed components" {
assert_eq(
(@tempo.Duration::hours(2L) + @tempo.Duration::minutes(30L)).humanize(),
"2 hours 30 minutes",
)
assert_eq(@tempo.Duration::seconds(1L).humanize(), "1 second")
assert_eq(
(@tempo.Duration::days(1L) +
@tempo.Duration::hours(1L) +
@tempo.Duration::minutes(1L) +
@tempo.Duration::seconds(1L)).humanize(),
"1 day 1 hour 1 minute 1 second",
)
assert_eq(@tempo.Duration::seconds(0L).humanize(), "0 seconds")
assert_eq(@tempo.Duration::milliseconds(500L).humanize(), "0 seconds")
assert_eq(@tempo.Duration::seconds(-5L).humanize(), "-5 seconds")
assert_eq(@tempo.Duration::minutes(-90L).humanize(), "-1 hour 30 minutes")
assert_eq(
@tempo.Duration::nanoseconds(-9_223_372_036_854_775_808L).humanize(),
"-106751 days 23 hours 47 minutes 16 seconds",
)
}

///|
test "Duration::parse_iso fixed-unit components" {
assert_eq(
Expand Down