From 27262a8fa4f5cb70880055297398da85bf9547c6 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Mon, 23 Nov 2020 12:28:53 -0700 Subject: [PATCH 1/4] Add support for human friendly duration formatting --- duration.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ duration_test.go | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 duration.go create mode 100644 duration_test.go diff --git a/duration.go b/duration.go new file mode 100644 index 0000000..ac60203 --- /dev/null +++ b/duration.go @@ -0,0 +1,58 @@ +package humanize + +import ( + "strconv" + "strings" + "time" +) + +type format struct { + key string + unit time.Duration + name string +} + +// Duration produces a formated duration as a string +// it supports the following format flags: +// %y - year +// %m - month +// %w - week +// %H - hour +// %M - minute +// %S - second +func Duration(format string, d time.Duration) string { + if format == "" { + format = "%y %m %w %d %H %M %S" + } + process := func(f string, unit time.Duration, name string) { + if strings.Contains(format, f) { + segment := int(d / unit) + format = strings.ReplaceAll(format, f, pluralize(segment, name)) + d %= unit + } + } + + process("%y", 365*Day, "year") + process("%m", Month, "month") + process("%w", Week, "week") + process("%d", Day, "day") + process("%H", time.Hour, "hour") + process("%M", time.Minute, "minute") + process("%S", time.Second, "second") + + // cleanup spaces + format = strings.Trim(format, " ") + return strings.ReplaceAll(format, " ", " ") +} + +func pluralize(i int, s string) string { + if i == 0 { + return "" + } + s = strconv.Itoa(i) + " " + s + + if i > 1 { + s += "s" + } + return s +} diff --git a/duration_test.go b/duration_test.go new file mode 100644 index 0000000..8970506 --- /dev/null +++ b/duration_test.go @@ -0,0 +1,47 @@ +package humanize + +import ( + "testing" + "time" +) + +func TestDuration(t *testing.T) { + type test struct { + format string + d time.Duration + expected string + } + cases := map[string]test{ + "default": { + format: "%y %m %w %d %H %M %S", + d: 400*Day + 12*time.Hour + 17*time.Second, + expected: "1 year 1 month 5 days 12 hours 17 seconds", + }, + "years": { + format: "%y", + d: 800 * Day, + expected: "2 years", + }, + "year + week": { + format: "%y %w", + d: 364 * Day, + expected: "52 weeks", + }, + "month + hours": { + format: "%w %H", + d: 15 * Day, + expected: "2 weeks 24 hours", + }, + "seconds only": { + format: "%S", + d: Day, + expected: "86400 seconds", + }, + } + for name, v := range cases { + result := Duration(v.format, v.d) + if result != v.expected { + t.Errorf("FAIL:%s\n\tExpected:%s\n\tActual:%s", name, v.expected, result) + } + } +} From b39fb21e7188b9b7dad761af5848ff834ea56dd4 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Tue, 24 Nov 2020 12:34:12 -0700 Subject: [PATCH 2/4] remove strings.ReplaceAll --- .travis.yml | 6 ++++++ duration.go | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ba95cdd..136437b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,12 @@ go: - 1.7.x - 1.8.x - 1.9.x + - 1.10.x + - 1.11.x + - 1.12.x + - 1.13.x + - 1.14.x + - 1.15.x - master matrix: allow_failures: diff --git a/duration.go b/duration.go index ac60203..21bafb0 100644 --- a/duration.go +++ b/duration.go @@ -27,7 +27,7 @@ func Duration(format string, d time.Duration) string { process := func(f string, unit time.Duration, name string) { if strings.Contains(format, f) { segment := int(d / unit) - format = strings.ReplaceAll(format, f, pluralize(segment, name)) + format = strings.Replace(format, f, pluralize(segment, name), -1) d %= unit } } @@ -42,7 +42,7 @@ func Duration(format string, d time.Duration) string { // cleanup spaces format = strings.Trim(format, " ") - return strings.ReplaceAll(format, " ", " ") + return strings.Replace(format, " ", " ", -1) } func pluralize(i int, s string) string { From 4f37380c717d30506f4bbfd54585c7c00c838809 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Wed, 25 Nov 2020 15:35:27 -0700 Subject: [PATCH 3/4] remove go vet from travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 136437b..8df8679 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,5 +23,4 @@ install: script: - go get -t -v ./... - diff -u <(echo -n) <(gofmt -d -s .) - - go tool vet . - go test -v -race ./... From dd429fb3ef7983b2a7d5f4ff0451919962236a72 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Fri, 12 Mar 2021 11:19:16 -0700 Subject: [PATCH 4/4] support negative durations --- duration.go | 4 ++++ duration_test.go | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/duration.go b/duration.go index 21bafb0..080257f 100644 --- a/duration.go +++ b/duration.go @@ -24,6 +24,10 @@ func Duration(format string, d time.Duration) string { if format == "" { format = "%y %m %w %d %H %M %S" } + if d < 0 { + format = "-" + format + d *= -1 + } process := func(f string, unit time.Duration, name string) { if strings.Contains(format, f) { segment := int(d / unit) diff --git a/duration_test.go b/duration_test.go index 8970506..b680006 100644 --- a/duration_test.go +++ b/duration_test.go @@ -17,11 +17,26 @@ func TestDuration(t *testing.T) { d: 400*Day + 12*time.Hour + 17*time.Second, expected: "1 year 1 month 5 days 12 hours 17 seconds", }, + "negative": { + format: "%y %m %w %d %H %M %S", + d: -(400*Day + 12*time.Hour + 17*time.Second), + expected: "-1 year 1 month 5 days 12 hours 17 seconds", + }, "years": { format: "%y", d: 800 * Day, expected: "2 years", }, + "zero": { + format: "%y", + d: 0, + expected: "", + }, + "neg years": { + format: "%y", + d: -800 * Day, + expected: "-2 years", + }, "year + week": { format: "%y %w", d: 364 * Day,