Skip to content

fix(template): render server-side dates in the site time zone with valid ISO-8601 markers - #1670

Open
NUAAwqy wants to merge 1 commit into
apache:devfrom
NUAAwqy:fix/server-rendered-dates-site-timezone
Open

NUAAwqy wants to merge 1 commit into
apache:devfrom
NUAAwqy:fix/server-rendered-dates-site-timezone

Conversation

@NUAAwqy

@NUAAwqy NUAAwqy commented Nov 12, 2026

Copy link
Copy Markdown

Fixes #1669

Root cause

The server-rendered dates ignore the site-configured time zone in three places (verified on dev; see #1669 for the full report and the executed repro):

  1. timeFormatISO (internal/base/server/http_funcmap.go) called time.LoadLocation(tz) and discarded the loaded location — the same pattern fix(day): render unix timestamps in the time zone the caller asked for #1659 fixed in day.Format — then formatted in the server's local zone with the layout 2006-01-02T15:04:05.000Z, where the trailing Z is a literal. Every server-rendered <time datetime="..."> (question detail ×4, comment, question list, tag detail) carried the server-local wall clock labeled as UTC.
  2. The JSON-LD DateCreated fields (internal/controller/template_controller.go) were built with time.Unix(...) in the server zone, so the schema.org data carried the deployment's zone instead of siteInfo.Interface.TimeZone.
  3. The same-year decision in translatorTimeFormat compared calendar years in the server zone, not the display zone: two instants sharing a year in Tokyo sit on opposite sides of New Year in Los Angeles.

Proposed changes

  • pkg/day: extract the shared zone resolver Location(tz) (empty/unknown → server local, the semantics fix(day): render unix timestamps in the time zone the caller asked for #1659 established) and add FormatISO(unix, tz) rendering a real ISO-8601 marker (+09:00, or Z only for UTC). Format now uses Location too (behavior unchanged on dev).
  • http_funcmap.go: timeFormatISO delegates to day.FormatISO; the dead LoadLocation call is removed; the year-boundary decision moves into sameYearInZone(a, b, tz) and is made in the display zone.
  • template_controller.go: the JSON-LD DateCreated values are rendered with .In(day.Location(siteInfo.Interface.TimeZone)).

Verification

All commands run with Go 1.25.14 (linux/amd64) on the dev branch with these changes applied.

  • go test ./pkg/day/ -v — TestFormat, TestFormatTimezone (5 subtests), TestFormatUnknownTimezoneFallsBackToLocal (3 subtests), TestLocation, TestFormatISO (5 subtests) — all PASS, ok github.com/apache/answer/pkg/day 0.368s.
  • go test ./internal/base/server/ -v — TestTimeFormatISO (4 subtests), TestTimeFormatISOFallsBackToLocalForUnknownZone (3 subtests), TestSameYearInZone — all PASS, ok github.com/apache/answer/internal/base/server 0.040s.
  • Before/after for the repro from Server-rendered <time datetime> and JSON-LD dates ignore the site time zone (server-local wall clock labeled as UTC) #1669 (process with TZ=Asia/Shanghai): before timeFormatISO("Asia/Tokyo", 1700000000) = 2023-11-15T06:13:20.000Z, after 2023-11-15T07:13:20.000+09:00.
  • go build ./... clean; go test ./internal/... ./pkg/... ./plugin/... ./cmd/... passes everywhere except internal/repo/repo_test and plugin/plugin_test, which panic on pristine dev too (the sandboxed sqlite cannot write: "attempt to write a readonly database") — pre-existing environment limitation, unrelated to this change.

Changelog

  • fix(template): render server-side <time datetime> attributes and JSON-LD dates in the site time zone with valid ISO-8601 markers, instead of the server-local wall clock labeled as UTC

…lid ISO-8601 markers

The timeFormatISO template func discarded the location loaded from the
site-configured time zone (the same pattern apache#1659 fixed in day.Format) and
formatted the server-local wall clock under a literal "Z", so every
server-rendered <time datetime="..."> attribute carried the wrong instant
labeled as UTC. The JSON-LD DateCreated values were built in the server zone
as well, and the same-year decision in translatorTimeFormat compared years in
the server zone instead of the display zone.

Add day.Location and day.FormatISO as the shared zone-aware renderer, route
timeFormatISO through it, drop the dead LoadLocation call, make the
same-year decision in the display zone, and render the JSON-LD dates with
.In(day.Location(siteInfo.Interface.TimeZone)).

Fixes apache#1669

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant