From 5761f92e16b9181a3ac24e02c74d01684830e86f Mon Sep 17 00:00:00 2001 From: stk Date: Sat, 2 May 2026 15:47:58 +0200 Subject: [PATCH 1/3] Make UnixToDateSmart timezone-deterministic The "custom time format" test case of TestGetCommitListDisplayStrings failed on Windows. Root cause: UnixToDateSmart used time.Unix(timestamp, 0), which formats in process-local time. In tests we pass an explicit 'now' (often UTC), but the timestamp was rendered in Local, causing one-hour drift on non-UTC machines. The test tried to work around this by doing os.Setenv("TZ", "UTC"); however, this only worked on Mac and Linux. On Windows, it has no effect because Windows uses registry-based timezone configuration, not TZ environment variables. Change: convert the timestamp into now.Location() before both the same-day comparison and formatting. Why this is safe: callers already define the presentation timezone via the 'now' argument (typically time.Now() in app code, controlled time in tests). This aligns timestamp rendering with that caller intent and removes dependence on global TZ state or OS-specific environment variable behavior. Added regression tests for UTC and UTC+1 to ensure deterministic behavior across all platforms. --- pkg/utils/date.go | 2 +- pkg/utils/date_test.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/pkg/utils/date.go b/pkg/utils/date.go index 9e8c84445..f0303a9c4 100644 --- a/pkg/utils/date.go +++ b/pkg/utils/date.go @@ -57,7 +57,7 @@ func formatSecondsAgo(secondsAgo int64) string { // formats the date in a smart way, if the date is today, it will show the time, otherwise it will show the date func UnixToDateSmart(now time.Time, timestamp int64, longTimeFormat string, shortTimeFormat string) string { - date := time.Unix(timestamp, 0) + date := time.Unix(timestamp, 0).In(now.Location()) if date.Day() == now.Day() && date.Month() == now.Month() && date.Year() == now.Year() { return date.Format(shortTimeFormat) diff --git a/pkg/utils/date_test.go b/pkg/utils/date_test.go index 0162f5f67..28ad65df8 100644 --- a/pkg/utils/date_test.go +++ b/pkg/utils/date_test.go @@ -2,6 +2,9 @@ package utils import ( "testing" + "time" + + "github.com/stretchr/testify/assert" ) func TestFormatSecondsAgo(t *testing.T) { @@ -95,3 +98,18 @@ func TestFormatSecondsAgo(t *testing.T) { }) } } + +func TestUnixToDateSmart_UsesNowLocationForFormatting(t *testing.T) { + timestamp := int64(1577844184) // 2020-01-01 02:03:04 UTC + now := time.Date(2020, 1, 1, 5, 3, 4, 0, time.UTC) + + assert.Equal(t, "2:03AM", UnixToDateSmart(now, timestamp, "2006-01-02", "3:04PM")) +} + +func TestUnixToDateSmart_SameTimestampDifferentNowLocation(t *testing.T) { + timestamp := int64(1577844184) // 2020-01-01 02:03:04 UTC + loc := time.FixedZone("UTC+1", 3600) + now := time.Date(2020, 1, 1, 6, 3, 4, 0, loc) + + assert.Equal(t, "3:03AM", UnixToDateSmart(now, timestamp, "2006-01-02", "3:04PM")) +} From 3ffc4ac8326ce2eb50132de3dfeb8d1067fbc0b0 Mon Sep 17 00:00:00 2001 From: stk Date: Sat, 2 May 2026 17:37:14 +0200 Subject: [PATCH 2/3] Remove now unnecessary Setenv call The call was meant to guarantee a UTC time zone to make the tests deterministic, but as the previous commit explained, this only worked on Mac and Linux, not on Windows. Since we now have a better fix, this workaround is no longer needed. --- pkg/gui/presentation/commits_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/gui/presentation/commits_test.go b/pkg/gui/presentation/commits_test.go index 1536d420a..972413e7b 100644 --- a/pkg/gui/presentation/commits_test.go +++ b/pkg/gui/presentation/commits_test.go @@ -1,7 +1,6 @@ package presentation import ( - "os" "strings" "testing" "time" @@ -531,8 +530,6 @@ func TestGetCommitListDisplayStrings(t *testing.T) { oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelNone) defer color.ForceSetColorLevel(oldColorLevel) - os.Setenv("TZ", "UTC") - focusing := false for _, scenario := range scenarios { if scenario.focus { From 7fbc2a8c14d016dc5923efddc4f2a926d3486aea Mon Sep 17 00:00:00 2001 From: stk Date: Sat, 2 May 2026 17:49:18 +0200 Subject: [PATCH 3/3] Close temp file handles before cleanup on Windows Windows cannot remove files while handles are still open. In TestOSCommandFileType we created files and immediately called RemoveAll without closing handles, which left untracked artifacts (e.g. "testFile" and "file with spaces") in the working tree. Close the handles and assert RemoveAll succeeds so cleanup failures are visible. --- pkg/commands/oscommands/os_test.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/commands/oscommands/os_test.go b/pkg/commands/oscommands/os_test.go index ecae92b18..54d9f3a80 100644 --- a/pkg/commands/oscommands/os_test.go +++ b/pkg/commands/oscommands/os_test.go @@ -91,7 +91,11 @@ func TestOSCommandFileType(t *testing.T) { { "testFile", func() { - if _, err := os.Create("testFile"); err != nil { + f, err := os.Create("testFile") + if err != nil { + panic(err) + } + if err := f.Close(); err != nil { panic(err) } }, @@ -102,7 +106,11 @@ func TestOSCommandFileType(t *testing.T) { { "file with spaces", func() { - if _, err := os.Create("file with spaces"); err != nil { + f, err := os.Create("file with spaces") + if err != nil { + panic(err) + } + if err := f.Close(); err != nil { panic(err) } }, @@ -133,7 +141,7 @@ func TestOSCommandFileType(t *testing.T) { for _, s := range scenarios { s.setup() s.test(FileType(s.path)) - _ = os.RemoveAll(s.path) + assert.NoError(t, os.RemoveAll(s.path)) } }