Date Header Feature: Regional Time Zones Not Represented
0 reputation · 06 Feb 2025, 04:56 UTC
0 reputation · 06 Feb 2025, 04:56 UTC
The Ktor Date feature injects a Date header using RFC 1123 formatting. Internally it relies on HttpDate, which always emits a GMT string, converting any supplied ZonedDateTime to UTC before formatting.
There is no documented option to preserve a regional time zone or customize the formatter. Developers who need to expose local time in the header face an uncertainty: should the feature be extended, or is the UTC-only implementation sufficient?
Date header in a specified regional time zone?Not through the built-in Date feature. Ktor's Date header path funnels through HttpDate, which normalizes the supplied temporal to UTC and formats it with the RFC 1123 GMT pattern. There is no configuration option to keep a regional offset. You can install a custom plugin that writes a zone-preserving string into Date, but that header is then non-compliant and unsafe for caching. The practical resolution is to leave Date in GMT and expose local time in a separate header.
Confirmed by the HTTP specifications: the HTTP-date format used by Date, Expires, Last-Modified and the conditional-request headers is defined with a literal GMT zone token. A numeric offset such as +0200 is not a valid HTTP-date, even though it is a valid RFC 1123 date in other contexts.
Version-dependent and worth checking in your own tree: that the Date feature delegates to HttpDate and converts to UTC before formatting. Read the source or decompiled class for the exact Ktor version you run rather than assuming the behavior is documented as a contract. The same applies to which plugin (default headers, date feature, or both) actually writes the header in your setup.
Date, Expires and Last-Modified as instants. A string they cannot parse reliably can be dropped, treated as absent, or mis-ordered.Date can shift the apparent freshness window and produce wrong 200 or 304 outcomes, which shows up as stale or over-fetched responses.Date stays GMT.X-Local-Date, and document its format for consumers.Illustrative formatting only; the plugin wiring differs between Ktor versions:
val local = ZonedDateTime.now(ZoneId.of("America/New_York"))
.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
// attach it to the response, e.g.:
// call.response.headers.append("X-Local-Date", local)curl -sI http://localhost:8080/ | grep -iE '^(date|x-local-date):'Check that Date still ends in GMT and that the local header carries the offset you expect. If you want to confirm the UTC normalization claim, exercise the formatter directly with a non-UTC ZonedDateTime and inspect the output string.
Who consumes the value? If the only reader is a client you control, no shared cache or CDN sits in front, and you never issue conditional requests, a non-GMT Date is merely non-standard rather than actively harmful. If any proxy, CDN or browser cache is in the path, keep Date in GMT and use the separate header.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.