diff --git a/internal/monitor/export_test.go b/internal/monitor/export_test.go index f330e5a..4bf82c1 100644 --- a/internal/monitor/export_test.go +++ b/internal/monitor/export_test.go @@ -2,6 +2,7 @@ package monitor import ( "context" + "time" "git.eeqj.de/sneak/rtnetmon/internal/starlink" ) @@ -59,6 +60,9 @@ func (m *Monitor) TCPHosts() []string { return m.tcpHosts } // Interfaces returns the monitored interfaces. func (m *Monitor) Interfaces() []*InterfaceStatus { return m.interfaces } +// ClockStrings exposes clockStrings for external tests. +func ClockStrings(now time.Time) (string, string) { return clockStrings(now) } + // PingArgs exposes pingArgs for external tests. func PingArgs(goos, iface, host string) []string { return pingArgs(goos, iface, host) } diff --git a/internal/monitor/ui.go b/internal/monitor/ui.go index 185fcbe..9044498 100644 --- a/internal/monitor/ui.go +++ b/internal/monitor/ui.go @@ -337,6 +337,15 @@ func drawICMPStats(scr tcell.Screen, y int, st *InterfaceStatus) int { } // uiLoop runs the UI event loop. +// clockFormat is the layout of both header clocks. +const clockFormat = time.RFC1123Z + +// clockStrings renders the header clocks: UTC first, then the host's local +// time in whatever location now carries. +func clockStrings(now time.Time) (string, string) { + return now.UTC().Format(clockFormat), now.Format(clockFormat) +} + func (m *Monitor) uiLoop(ctx context.Context) { m.logf("UI loop started") @@ -348,13 +357,6 @@ func (m *Monitor) uiLoop(ctx context.Context) { m.logf("Screen finalized") }() - pstLoc, err := time.LoadLocation("America/Los_Angeles") - if err != nil { - m.logf("Error loading PST location: %v", err) - - pstLoc = time.UTC - } - timestampSpinFrame := 0 lastTimestampSpinUpdate := time.Now() @@ -365,8 +367,7 @@ func (m *Monitor) uiLoop(ctx context.Context) { Put(m.screen, colLeft, rowTopRule, HLine(w), tcell.StyleDefault) now := time.Now() - timeStr := now.Format(time.RFC1123Z) - pstTimeStr := now.In(pstLoc).Format(time.RFC1123Z) + timeStr, localTimeStr := clockStrings(now) if time.Since(lastTimestampSpinUpdate) >= time.Second { timestampSpinFrame = (timestampSpinFrame + 1) % len(brailleSpins()) @@ -380,7 +381,7 @@ func (m *Monitor) uiLoop(ctx context.Context) { Put(m.screen, colSpinner, rowClock, string(brailleChar)+" ", tcell.StyleDefault) DrawRainbowText(m.screen, colMeter, rowClock, timeStr, colors) DrawRainbowText(m.screen, colMeter+len(timeStr)+clockGap, rowClock, - pstTimeStr, colors) + localTimeStr, colors) Put(m.screen, colLeft, rowBottomRule, HLine(w), tcell.StyleDefault) runtime := time.Since(m.startTime).Round(time.Second).String() diff --git a/internal/monitor/ui_test.go b/internal/monitor/ui_test.go new file mode 100644 index 0000000..5a072be --- /dev/null +++ b/internal/monitor/ui_test.go @@ -0,0 +1,27 @@ +package monitor_test + +import ( + "testing" + "time" + + "git.eeqj.de/sneak/rtnetmon/internal/monitor" +) + +// TestClockStrings checks that the header shows UTC first and the host's +// local time second, so the two differ whenever the host is not on UTC. +func TestClockStrings(t *testing.T) { + t.Parallel() + + berlin := time.FixedZone("CET", 3600) + now := time.Date(2026, time.November, 6, 20, 30, 0, 0, berlin) + + utc, local := monitor.ClockStrings(now) + + if want := "Fri, 06 Nov 2026 19:30:00 +0000"; utc != want { + t.Errorf("utc = %q, want %q", utc, want) + } + + if want := "Fri, 06 Nov 2026 20:30:00 +0100"; local != want { + t.Errorf("local = %q, want %q", local, want) + } +}