elvish
elvish copied to clipboard
RFC: Should there be a `human-readable-duration` command?
With the resolution of issue #1029 we now have a $edit:command-duration
variable. However, it is a simple float64
of the fractional number of seconds the command took to complete; e.g., 3.141592653589793. Which isn't friendly when displayed in a prompt. I have a utility function that converts that into a scaled human friendly string. There are two questions:
-
Is there enough consensus on how durations should be formatted for use in a prompt that adding a
human-readable-duration
command as a builtin is useful? -
When issue #1030 is resolved the
$edit:command-duration
variable will probably be changed from afloat64
to a Gotime.Duration
. That would have an implicit conversion to a string using itsString()
interface. People may feel that string representation is good enough for use in a prompt. In which case is an explicit command still necessary?
This is the function I currently use:
fn human-readable [duration]{
if (> 0.001 $duration) {
# Up to one millisecond display microseconds.
printf '%.0f µs' (* $duration 1_000_000)
} elif (> 1 $duration) {
# Up to one second display milliseconds.
printf '%.1f ms' (* $duration 1_000)
} elif (> 60 $duration) {
# Up to one minute display fractional seconds.
printf '%.1f s' $duration
} elif (> 3600 $duration) {
# Up to one hour display fractional minutes.
printf '%.1f m' (/ $duration 60)
} else {
# Otherwise display fractional hours.
printf '%.1f h' (/ $duration 3600)
}
}
This table shows how various durations would be represented by both solutions:
raw seconds | time.Duration.String() | human-readable |
---|---|---|
0.000243 | 243µs | 243 µs |
0.456789 | 456.789ms | 456.8 ms |
3.141592 | 3.141592s | 3.1 s |
789.123456 | 13m9.123456s | 13.2 m |
7890.123456 | 2h11m30.123456s | 2.2 h |
@krader1961 I think your function is a good start, but I'd argue that most people don't usually deal with fractional minutes nor hours. Instead of those, I think the fraction should be converted to seconds/minutes, respectively, e.g.:
raw seconds | human-readable |
---|---|
789.123456 | 13m9s |
7890.123456 | 2h11m30s |
BTW this is how Starship's cmd_duration
module prints times, I was lazy to figure out the calculation for these examples so they were generated as follows:
~ |> starship prompt --cmd-duration 789123
~ ⏱ 13m9s|>
~ |> starship prompt --cmd-duration 7890123
~ ⏱ 2h11m30s|>
Well, if I need to choose between 13m9.123456s and 13.2 m, I'd say the former is actually closer to the human-readable form.
@zzamboni's proposal can already be expressed in Go by using duration.Truncate to first truncate the duration to seconds:
package main
import (
"fmt"
"time"
)
func main() {
t1 := time.Millisecond * 789123
t2 := time.Millisecond * 7890123
fmt.Println(t1.Truncate(time.Second))
fmt.Println(t2.Truncate(time.Second))
}
~/tmp> go run t.go
13m9s
2h11m30s
So I don't think the command is necessary if we have a binding for the Duration.Truncate method.
Thanks for the feedback which illustrates why this is likely to be a highly subjective matter regarding the optimal presentation of this data. I deliberately use fractional minutes or hours for a couple of reasons. First, and most importantly, because when I'm looking at this info in the prompt I'm not really interested in the exact duration. I'm interested in the magnitude and something like 2.1 m
or 1.8 h
is adequate. I don't really care if it was 2m6.123s
or 1h48m10.123s
. Second, for consistency with the fractional seconds and milliseconds format. Third, because having a single unit at the end of the string makes the string as short as possible and that single unit conveys the most important fact about the value.
So I don't think the command is necessary if we have a binding for the Duration.Truncate method.
I don't grok how that solves the problem since even if we have such a binding the user still has to explicitly use it before coercing the duration to a string. And that requires logic equivalent to the example function I provided since I don't want to truncate to the nearest second if the duration is sub second. So it seems like we would still want a convenience command rather than forcing every user to reinvent this wheel.
What we probably need is a couple of predefined formats that can be selected by an option; e.g., human-readable &minimal
or human-readable &detailed
for my preferred format or the time.Duration format respectively.
I deliberately use fractional minutes or hours for a couple of reasons.
@zzamboni: It's also worth pointing out that people talk in terms of fractional minutes and hours all the time in my experience. For example, two and a half hours (2.5 h) from now. It is, however, rare for such cases to use any fraction other than half (0.5), quarter (0.25) or third (0.33). But that is consistent with my point that at that scale the exact number of seconds or minutes (the fractional portion of the value) is less important in the prompt than whether it is < 0.5, == 0.5, or > 0.5 of the major unit (e.g., seconds, minutes or hours).
For anyone who stumbles upon this issue in the future I've published my cmd-duration:human-readable
function. I still feel something like it should be included in the base Elvish program since it is a) extremely small (relative to the size of the elvish binary), and b) likely to be used by anyone wanting to display the previous command duration in their prompt in a human friendly form.
Closing since the presentation of command duration in the prompt is highly personal and it is unlikely there will ever be enough consensus to justify including an Elvish function with the shell to render that information. Even with options like &minimal
and &detailed
per my prior comment.