Add humanizeDuration function.

This attempts to reasonably handle things from weekly cronjobs,
to rpcs taking ns to things that are usually ms but jump to over a second.

For consistency, stop putting spaces before prefixes.

Change-Id: I6407879187b25680b323cd70254e205315b5fc3c
This commit is contained in:
Brian Brazil 2014-06-11 11:32:19 +01:00
parent 859c3b071d
commit fce3873b02
2 changed files with 63 additions and 10 deletions

View File

@ -138,7 +138,7 @@ func NewTemplateExpander(text string, name string, data interface{}, timestamp c
},
"humanize": func(v float64) string {
if v == 0 {
return fmt.Sprintf("%.4g ", v)
return fmt.Sprintf("%.4g", v)
}
if math.Abs(v) >= 1 {
prefix := ""
@ -149,7 +149,7 @@ func NewTemplateExpander(text string, name string, data interface{}, timestamp c
prefix = p
v /= 1000
}
return fmt.Sprintf("%.4g %s", v, prefix)
return fmt.Sprintf("%.4g%s", v, prefix)
} else {
prefix := ""
for _, p := range []string{"m", "u", "n", "p", "f", "a", "z", "y"} {
@ -159,12 +159,12 @@ func NewTemplateExpander(text string, name string, data interface{}, timestamp c
prefix = p
v *= 1000
}
return fmt.Sprintf("%.4g %s", v, prefix)
return fmt.Sprintf("%.4g%s", v, prefix)
}
},
"humanize1024": func(v float64) string {
if math.Abs(v) <= 1 {
return fmt.Sprintf("%.4g ", v)
return fmt.Sprintf("%.4g", v)
}
prefix := ""
for _, p := range []string{"ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"} {
@ -174,7 +174,45 @@ func NewTemplateExpander(text string, name string, data interface{}, timestamp c
prefix = p
v /= 1024
}
return fmt.Sprintf("%.4g %s", v, prefix)
return fmt.Sprintf("%.4g%s", v, prefix)
},
"humanizeDuration": func(v float64) string {
if v == 0 {
return fmt.Sprintf("%.4gs", v)
}
if math.Abs(v) >= 1 {
sign := ""
if v < 0 {
sign = "-"
v = -v
}
seconds := math.Mod(v, 60)
minutes := (int64(v) / 60) % 60
hours := (int64(v) / 60 / 60) % 24
days := (int64(v) / 60 / 60 / 24)
// For days to minutes, we display seconds as an integer.
if days != 0 {
return fmt.Sprintf("%s%dd %dh %dm %.0fs", sign, days, hours, minutes, seconds)
}
if hours != 0 {
return fmt.Sprintf("%s%dh %dm %.0fs", sign, hours, minutes, seconds)
}
if minutes != 0 {
return fmt.Sprintf("%s%dm %.0fs", sign, minutes, seconds)
}
// For seconds, we display 4 significant digts.
return fmt.Sprintf("%s%.4gs", sign, math.Floor(seconds*1000+.5)/1000)
} else {
prefix := ""
for _, p := range []string{"m", "u", "n", "p", "f", "a", "z", "y"} {
if math.Abs(v) >= 1 {
break
}
prefix = p
v *= 1000
}
return fmt.Sprintf("%.4g%ss", v, prefix)
}
},
},
}

View File

@ -24,6 +24,7 @@ import (
type testTemplatesScenario struct {
text string
output string
input interface{}
shouldFail bool
html bool
}
@ -104,13 +105,27 @@ func TestTemplateExpansion(t *testing.T) {
},
{
// Humanize.
text: "{{ 0.0 | humanize }}:{{ 1.0 | humanize }}:{{ 1234567.0 | humanize }}:{{ .12 | humanize }}",
output: "0 :1 :1.235 M:120 m",
text: "{{ range . }}{{ humanize . }}:{{ end }}",
input: []float64{0.0, 1.0, 1234567.0, .12},
output: "0:1:1.235M:120m:",
},
{
// Humanize1024.
text: "{{ 0.0 | humanize1024 }}:{{ 1.0 | humanize1024 }}:{{ 1048576.0 | humanize1024 }}:{{ .12 | humanize1024}}",
output: "0 :1 :1 Mi:0.12 ",
text: "{{ range . }}{{ humanize1024 . }}:{{ end }}",
input: []float64{0.0, 1.0, 1048576.0, .12},
output: "0:1:1Mi:0.12:",
},
{
// HumanizeDuration - seconds.
text: "{{ range . }}{{ humanizeDuration . }}:{{ end }}",
input: []float64{0, 1, 60, 3600, 86400, 86400 + 3600, -(86400*2 + 3600*3 + 60*4 + 5)},
output: "0s:1s:1m 0s:1h 0m 0s:1d 0h 0m 0s:1d 1h 0m 0s:-2d 3h 4m 5s:",
},
{
// HumanizeDuration - subsecond and fractional seconds.
text: "{{ range . }}{{ humanizeDuration . }}:{{ end }}",
input: []float64{.1, .0001, .12345, 60.1, 60.5, 1.2345, 12.345},
output: "100ms:100us:123.5ms:1m 0s:1m 0s:1.235s:12.35s:",
},
{
// Title.
@ -145,7 +160,7 @@ func TestTemplateExpansion(t *testing.T) {
for _, s := range scenarios {
var result string
var err error
expander := NewTemplateExpander(s.text, "test", nil, time, ts)
expander := NewTemplateExpander(s.text, "test", s.input, time, ts)
if s.html {
result, err = expander.ExpandHTML(nil)
} else {