From 719ce6eb5173115a5807a9934a4050fcfef2b1f7 Mon Sep 17 00:00:00 2001 From: Laurent Demailly Date: Thu, 11 Sep 2025 12:56:34 -0700 Subject: [PATCH 1/3] Add the Var and FlagSet variants for completeness --- duration.go | 28 +++++++++++++++++++++++++--- duration_test.go | 10 ++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/duration.go b/duration.go index 22c7060..6d2fff3 100644 --- a/duration.go +++ b/duration.go @@ -95,6 +95,11 @@ func Parse(s string) (time.Duration, error) { return d, nil } +// Duration is like [time.Duration] but supports days (24h) and weeks (7d) in addition to the +// units supported by [time.Duration]. This is mostly for internal use for the [Flag] function +// which still returns a standard duration for compatibility. Or if you want the more compact +// formatting with days and weeks and no zeroes in [Duration.String]. +// //nolint:recvcheck // need pointer receiver obviously for Set and for String avoids pointer. type Duration time.Duration @@ -185,11 +190,28 @@ func (d *Duration) Set(s string) error { // Flag defines a duration flag with the specified name, default value, and usage string, like // [flag.Duration] but supporting durations in days (24 hours) and weeks (7 days) -// in addition to the other stdlib units. +// in addition to the other stdlib units. Replacement for [flag.Duration]. func Flag(name string, value time.Duration, usage string) *time.Duration { + return FlagSet(flag.CommandLine, name, value, usage) +} + +// FlagSet is like [Flag] but for the specified flag set. Replacement for [flag.FlagSet.Duration]. +func FlagSet(fs *flag.FlagSet, name string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + FlagSetVar(fs, p, name, value, usage) + return p +} + +// FlagVar is like [Flag] but binds the value to variable referenced. Replacement for [flag.DurationVar]. +func FlagVar(p *time.Duration, name string, value time.Duration, usage string) { + FlagSetVar(flag.CommandLine, p, name, value, usage) +} + +// FlagSet is like [FlagVar] but for the specified flag set. Replacement for [flag.FlagSet.DurationVar]. +func FlagSetVar(fs *flag.FlagSet, p *time.Duration, name string, value time.Duration, usage string) { d := Duration(value) - flag.Var(&d, name, usage) - return (*time.Duration)(&d) + fs.Var((*Duration)(p), name, usage) + *p = time.Duration(d) } // NextTime takes a partially parsed time.Time (without date) and returns the time in the future diff --git a/duration_test.go b/duration_test.go index a2fc50d..21ebdc5 100644 --- a/duration_test.go +++ b/duration_test.go @@ -80,6 +80,16 @@ func TestFlag(t *testing.T) { } } +func TestFlagVar(t *testing.T) { + defaultValue, _ := duration.Parse("1d3m") + var d time.Duration + duration.FlagVar(&d, "test2", defaultValue, "test `duration`") + flag.Lookup("test2").Value.Set("1d1h") + if d != 25*time.Hour { + t.Errorf("Expected 25h but got %v", d) + } +} + func TestParseDateTime(t *testing.T) { l, err := time.LoadLocation("America/New_York") if err != nil { From 54b0ad81ac6729bc9c26c78b9fc080c0638f68bf Mon Sep 17 00:00:00 2001 From: Laurent Demailly Date: Thu, 11 Sep 2025 13:12:28 -0700 Subject: [PATCH 2/3] Added Example for flag too --- duration_test.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/duration_test.go b/duration_test.go index 21ebdc5..fd3cc2a 100644 --- a/duration_test.go +++ b/duration_test.go @@ -157,7 +157,7 @@ func TestParseDateTimeIsLocal(t *testing.T) { } } -func Example() { +func ExampleParse() { d, err := duration.Parse("1w 2d 3h 4m") if err != nil { fmt.Println("Error:", err) @@ -169,3 +169,19 @@ func Example() { // Parsed duration (std): 219h4m0s // Parsed duration (new): 1w2d3h4m } + +func ExampleFlag() { + f := duration.Flag("duration-flag", 1*duration.Day, "test `duration`") + // and then use *f normally and the users can use days, weeks etc. + + // to test/show: + flv := flag.Lookup("duration-flag").Value + fmt.Println("Default:", flv.String()) + flv.Set("1d1h") // no error + fmt.Println("After set:", flv.String()) + fmt.Println("After set (dereferenced):", *f) + // Output: + // Default: 1d + // After set: 1d1h + // After set (dereferenced): 25h0m0s +} From 7f4d36b4fd6407b9dc2b10db93603cb73511a295 Mon Sep 17 00:00:00 2001 From: Laurent Demailly Date: Thu, 11 Sep 2025 13:16:32 -0700 Subject: [PATCH 3/3] more package doc --- duration.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/duration.go b/duration.go index 6d2fff3..826ef5c 100644 --- a/duration.go +++ b/duration.go @@ -1,4 +1,8 @@ // Package duration allows duration parsing with "d" for days (24 hours) and "w" for week (7 days). +// For output direction, it implements a more human friendly formatting of durations removing +// all 0 values and using days and weeks when applicable. +// Includes helpers for command line flag duration parsing and for date/time parsing replacement. +// See also [fortio.org/dflag] if you need dynamic flags with days/weeks support. package duration import (