diff --git a/locate/install.go b/locate/install.go index 422c3e8de..1c1807cce 100644 --- a/locate/install.go +++ b/locate/install.go @@ -6,8 +6,8 @@ import ( ) func (po *LocateOptions) installGenericFlags(flags *flag.FlagSet) { - flags.Var(NewTimeFlag(&po.Filters.Before), "before", "filter by date") - flags.Var(NewTimeFlag(&po.Filters.Since), "since", "filter by date") + flags.Var(NewDurationFlag(&po.Filters.Before), "before", "filter by date") + flags.Var(NewDurationFlag(&po.Filters.Since), "since", "filter by date") flags.StringVar(&po.Filters.Name, "name", "", "filter by name") flags.StringVar(&po.Filters.Category, "category", "", "filter by category") diff --git a/locate/locate.go b/locate/locate.go index af8b3994c..0a9e50bd5 100644 --- a/locate/locate.go +++ b/locate/locate.go @@ -126,8 +126,8 @@ func (lp *LocatePeriod) Empty() bool { } type LocateFilters struct { - Before time.Time `json:"before,omitempty" yaml:"before,omitempty"` - Since time.Time `json:"since,omitempty" yaml:"since,omitempty"` + Before time.Duration `json:"before,omitempty" yaml:"before,omitempty"` + Since time.Duration `json:"since,omitempty" yaml:"since,omitempty"` Name string `json:"name,omitempty" yaml:"name,omitempty"` Category string `json:"category,omitempty" yaml:"category,omitempty"` @@ -215,10 +215,10 @@ func WithPerFridayCap(n int) Option { return func(p *LocateOptions) { p.Period func WithPerSaturdayCap(n int) Option { return func(p *LocateOptions) { p.Periods.Saturday.Cap = n } } func WithPerSundaysCap(n int) Option { return func(p *LocateOptions) { p.Periods.Sunday.Cap = n } } -func WithBefore(t time.Time) Option { +func WithBefore(t time.Duration) Option { return func(p *LocateOptions) { p.Filters.Before = t } } -func WithSince(t time.Time) Option { +func WithSince(t time.Duration) Option { return func(p *LocateOptions) { p.Filters.Since = t } } func WithName(name string) Option { @@ -261,11 +261,13 @@ func (lo *LocateOptions) Matches(it Item) bool { } } + now := time.Now() + // time window - if !lo.Filters.Before.IsZero() && it.Timestamp.After(lo.Filters.Before.UTC()) { + if lo.Filters.Before != 0 && it.Timestamp.After(now.Add(-lo.Filters.Before).UTC()) { return false } - if !lo.Filters.Since.IsZero() && it.Timestamp.Before(lo.Filters.Since.UTC()) { + if lo.Filters.Since != 0 && it.Timestamp.Before(now.Add(-lo.Filters.Since).UTC()) { return false } @@ -454,5 +456,5 @@ func (lo *LocateOptions) Empty() bool { lo.Filters.Name == "" && lo.Filters.Category == "" && lo.Filters.Environment == "" && lo.Filters.Perimeter == "" && lo.Filters.Job == "" && len(lo.Filters.Tags) == 0 && len(lo.Filters.IDs) == 0 && len(lo.Filters.Roots) == 0 && - lo.Filters.Before.IsZero() && lo.Filters.Since.IsZero() && !lo.Filters.Latest + lo.Filters.Before == 0 && lo.Filters.Since == 0 && !lo.Filters.Latest } diff --git a/locate/time.go b/locate/time.go index 39fb8c62d..a69f73bb2 100644 --- a/locate/time.go +++ b/locate/time.go @@ -80,3 +80,44 @@ func ParseTimeFlag(input string) (time.Time, error) { return time.Time{}, fmt.Errorf("invalid time format: %q", input) } + +// DurationFlag implements flag.Value interface +type DurationFlag struct { + dest *time.Duration +} + +func NewDurationFlag(dest *time.Duration) *DurationFlag { + return &DurationFlag{dest} +} + +func (t *DurationFlag) String() string { + if t.dest == nil || *t.dest == 0 { + return "" + } + return t.dest.String() +} + +func (t *DurationFlag) Set(s string) error { + parsed, err := ParseDurationFlag(s) + if err != nil { + return err + } + *t.dest = parsed + return nil +} + +func ParseDurationFlag(input string) (time.Duration, error) { + if strings.TrimSpace(input) != input { + return 0, fmt.Errorf("invalid time format: %q", input) + } + + if input == "" { + return 0, nil + } + + d, err := human2duration.ParseDuration(input) + if err != nil { + return 0, fmt.Errorf("invalid duration %q: %w", input, err) + } + return d, err +}