Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions commands/grep.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ var GrepCommand *cli.Command = &cli.Command{
},
&cli.StringFlag{
Name: "since",
Usage: "filter commands since date (2024, 2024-01, or 2024-01-15)",
Usage: "filter commands since date in local time (2024, 2024-01, or 2024-01-15)",
},
&cli.StringFlag{
Name: "until",
Usage: "filter commands until date (2024, 2024-01, or 2024-01-15)",
Usage: "filter commands until date in local time (2024, 2024-01, or 2024-01-15)",
},
},
Action: commandGrep,
Expand Down Expand Up @@ -237,31 +237,33 @@ func buildGrepFilter(c *cli.Context, searchText string) (*model.SearchCommandsFi
}

// parseFlexibleDate parses dates in formats: 2024, 2024-01, 2024-01-15
// If isEndOfPeriod is true, returns end of the period (for --until)
// If isEndOfPeriod is true, returns end of the period (for --until).
// Dates are calendar days of the machine's timezone, like everything else the
// user sees in the terminal; the server only receives the resulting instants.
func parseFlexibleDate(s string, isEndOfPeriod bool) (time.Time, error) {
// Try year only: 2024
if t, err := time.Parse("2006", s); err == nil {
if t, err := time.ParseInLocation("2006", s, time.Local); err == nil {
if isEndOfPeriod {
return time.Date(t.Year(), 12, 31, 23, 59, 59, 0, time.UTC), nil
return time.Date(t.Year(), 12, 31, 23, 59, 59, 0, time.Local), nil
}
return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, time.UTC), nil
return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, time.Local), nil
}

// Try year-month: 2024-01
if t, err := time.Parse("2006-01", s); err == nil {
if t, err := time.ParseInLocation("2006-01", s, time.Local); err == nil {
if isEndOfPeriod {
// End of month: go to next month, then subtract 1 second
return t.AddDate(0, 1, 0).Add(-time.Second), nil
}
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC), nil
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.Local), nil
}

// Try year-month-day: 2024-01-15
if t, err := time.Parse("2006-01-02", s); err == nil {
if t, err := time.ParseInLocation("2006-01-02", s, time.Local); err == nil {
if isEndOfPeriod {
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, time.UTC), nil
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, time.Local), nil
}
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.UTC), nil
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local), nil
}

return time.Time{}, fmt.Errorf("use format: 2024, 2024-01, or 2024-01-15")
Expand Down
32 changes: 23 additions & 9 deletions commands/grep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,21 @@ func setupGrepActionTest(t *testing.T) *model.MockConfigService {
func TestParseFlexibleDate_YearStart(t *testing.T) {
got, err := parseFlexibleDate("2024", false)
require.NoError(t, err)
want := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
want := time.Date(2024, 1, 1, 0, 0, 0, 0, time.Local)
assert.True(t, got.Equal(want), "got %v want %v", got, want)
}

func TestParseFlexibleDate_YearEnd(t *testing.T) {
got, err := parseFlexibleDate("2024", true)
require.NoError(t, err)
want := time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC)
want := time.Date(2024, 12, 31, 23, 59, 59, 0, time.Local)
assert.True(t, got.Equal(want), "got %v want %v", got, want)
}

func TestParseFlexibleDate_YearMonthStart(t *testing.T) {
got, err := parseFlexibleDate("2024-02", false)
require.NoError(t, err)
want := time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC)
want := time.Date(2024, 2, 1, 0, 0, 0, 0, time.Local)
assert.True(t, got.Equal(want), "got %v want %v", got, want)
}

Expand All @@ -77,17 +77,31 @@ func TestParseFlexibleDate_YearMonthEnd_NonLeapFeb(t *testing.T) {
func TestParseFlexibleDate_FullDateStart(t *testing.T) {
got, err := parseFlexibleDate("2024-01-15", false)
require.NoError(t, err)
want := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
want := time.Date(2024, 1, 15, 0, 0, 0, 0, time.Local)
assert.True(t, got.Equal(want), "got %v want %v", got, want)
}

func TestParseFlexibleDate_FullDateEnd(t *testing.T) {
got, err := parseFlexibleDate("2024-01-15", true)
require.NoError(t, err)
want := time.Date(2024, 1, 15, 23, 59, 59, 0, time.UTC)
want := time.Date(2024, 1, 15, 23, 59, 59, 0, time.Local)
assert.True(t, got.Equal(want), "got %v want %v", got, want)
}

func TestParseFlexibleDate_UsesMachineTimezone(t *testing.T) {
saved := time.Local
time.Local = time.FixedZone("JST", 9*3600)
t.Cleanup(func() { time.Local = saved })

start, err := parseFlexibleDate("2024-01-15", false)
require.NoError(t, err)
assert.Equal(t, time.Date(2024, 1, 14, 15, 0, 0, 0, time.UTC).Unix(), start.Unix(), "local midnight in Tokyo")

end, err := parseFlexibleDate("2024-01", true)
require.NoError(t, err)
assert.Equal(t, time.Date(2024, 1, 31, 14, 59, 59, 0, time.UTC).Unix(), end.Unix())
}

func TestParseFlexibleDate_Garbage(t *testing.T) {
for _, in := range []string{"not-a-date", "20", "2024-13-99-extra", ""} {
t.Run(in, func(t *testing.T) {
Expand Down Expand Up @@ -176,10 +190,10 @@ func TestBuildGrepFilter_SinceAndUntilTimeWindow(t *testing.T) {

// The server reads the window in unix seconds.
require.Len(t, filter.Time, 2)
since := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
since := time.Date(2024, 1, 1, 0, 0, 0, 0, time.Local)
assert.Equal(t, float64(since.Unix()), filter.Time[0])
// until=2024-06 end-of-period -> 2024-06-30 23:59:59 UTC.
untilEnd := time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)
untilEnd := time.Date(2024, 6, 30, 23, 59, 59, 0, time.Local)
assert.Equal(t, float64(untilEnd.Unix()), filter.Time[1])
}

Expand All @@ -192,7 +206,7 @@ func TestBuildGrepFilter_SinceOnlyRunsUntilNow(t *testing.T) {

// A single value would be read as "that one day", so the end is filled in.
require.Len(t, filter.Time, 2)
since := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
since := time.Date(2024, 1, 15, 0, 0, 0, 0, time.Local)
assert.Equal(t, float64(since.Unix()), filter.Time[0])
assert.InDelta(t, float64(time.Now().Unix()), filter.Time[1], 5)
}
Expand All @@ -206,7 +220,7 @@ func TestBuildGrepFilter_UntilOnlyStartsAtEpoch(t *testing.T) {

require.Len(t, filter.Time, 2)
assert.Equal(t, float64(0), filter.Time[0])
untilEnd := time.Date(2024, 1, 15, 23, 59, 59, 0, time.UTC)
untilEnd := time.Date(2024, 1, 15, 23, 59, 59, 0, time.Local)
assert.Equal(t, float64(untilEnd.Unix()), filter.Time[1])
}

Expand Down
Loading