elvish icon indicating copy to clipboard operation
elvish copied to clipboard

RFC: Should there be a `human-readable-duration` command?

Open krader1961 opened this issue 3 years ago • 5 comments

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:

  1. 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?

  2. When issue #1030 is resolved the $edit:command-duration variable will probably be changed from a float64 to a Go time.Duration. That would have an implicit conversion to a string using its String() 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 avatar May 06 '21 02:05 krader1961

@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|>

zzamboni avatar May 06 '21 08:05 zzamboni

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.

xiaq avatar May 06 '21 10:05 xiaq

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.

krader1961 avatar May 07 '21 01:05 krader1961

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).

krader1961 avatar May 11 '21 04:05 krader1961

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.

krader1961 avatar Jun 28 '22 02:06 krader1961

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.

krader1961 avatar Aug 11 '22 01:08 krader1961