diff --git a/cmd/mavweb/events.html b/cmd/mavweb/events.html index a344c98..d1acafe 100644 --- a/cmd/mavweb/events.html +++ b/cmd/mavweb/events.html @@ -14,8 +14,13 @@ memory only, so a restart empties this.
| noticed | happened | source | kind | pri | what | detail | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{.NoticedAt.Format "02.01 15:04:05"}} | -{{.OccurredAt.Format "02.01 15:04:05"}} | + +{{.NoticedAt.Local.Format "02.01 15:04:05"}} | +{{.OccurredAt.Local.Format "02.01 15:04:05"}} | {{.Source}} | {{.Kind}} | {{.Priority}} | diff --git a/cmd/mavweb/events_test.go b/cmd/mavweb/events_test.go index 2d86102..0e280b2 100644 --- a/cmd/mavweb/events_test.go +++ b/cmd/mavweb/events_test.go @@ -46,7 +46,8 @@ func TestEventsPageRendersTheJournal(t *testing.T) { t.Fatalf("status = %d, want 200", w.Code) } body := w.Body.String() - for _, want := range []string{"rss:tech", "Вышло ядро 6.19", "ambient:notif", "10:00-11:00 планёрка", "01.08 10:00:00"} { + occurred := time.Date(2026, 8, 1, 10, 0, 0, 0, time.UTC).Local().Format("02.01 15:04:05") + for _, want := range []string{"rss:tech", "Вышло ядро 6.19", "ambient:notif", "10:00-11:00 планёрка", occurred} { if !strings.Contains(body, want) { t.Errorf("page does not mention %q", want) } @@ -89,6 +90,38 @@ func TestEventsPageWithoutCore(t *testing.T) { } } +// awayFromLocal returns a zone three hours off whatever this machine runs in, +// so a test can tell "rendered in his clock" apart from "rendered in whatever +// zone the value arrived in" without depending on TZ. +func awayFromLocal() *time.Location { + _, off := time.Now().Zone() + return time.FixedZone("away", off+3*60*60) +} + +func TestEventsPageRendersBothTimesInLocalZone(t *testing.T) { + // OccurredAt carries the source's zone — the store hands back UTC and + // internal/rss parses a pubDate to UTC — while NoticedAt is the bus's local + // instant. Rendered raw, the two columns of one row were in two zones and a + // feed item read hours older than it was. + away := awayFromLocal() + occurred := time.Date(2026, 8, 1, 7, 15, 0, 0, time.UTC).In(away) + noticed := occurred.Add(2 * time.Minute) + core := &eventsCore{events: []ipc.IntakeEvent{{ + Source: "rss:tech", Kind: "note", Title: "Вышло ядро 6.19", Priority: "low", + OccurredAt: occurred, NoticedAt: noticed, + }}} + body := getEvents(t, core).Body.String() + const layout = "02.01 15:04:05" + for _, ts := range []time.Time{occurred, noticed} { + if !strings.Contains(body, ts.Local().Format(layout)) { + t.Errorf("page does not render %s in his clock (%s)", ts, ts.Local().Format(layout)) + } + if strings.Contains(body, ts.In(away).Format(layout)) { + t.Errorf("page rendered %s in the source's zone", ts) + } + } +} + func TestEventsPageEscapesIntakeText(t *testing.T) { // Titles come from outside — a feed headline, a notification. They are shown // on a page and must never be able to inject markup into it. diff --git a/cmd/mavweb/morning.html b/cmd/mavweb/morning.html index 3db912e..3de5827 100644 --- a/cmd/mavweb/morning.html +++ b/cmd/mavweb/morning.html @@ -8,7 +8,10 @@
| at | kind | what | |
|---|---|---|---|
| {{.At.Format "15:04"}} | + +{{.At.Local.Format "15:04"}} | {{.Kind}} | {{if .Uncertain}}похоже, {{end}}{{.Text}} |