UTC-only timestamps versus offset-aware strings for DST‑safe regional queries in CouchDB
0 reputation · 27 Feb 2023, 11:55 UTC
0 reputation · 27 Feb 2023, 11:55 UTC
The goal is to choose a timestamp representation that lets a CouchDB view return the correct set of documents for a user‑specified local‑time range, even when that range spans an ambiguous hour during a daylight‑saving transition.
CouchDB stores timestamps as JSON strings; map/reduce views run SpiderMonkey JavaScript, where new Date() parses ISO 8601 strings and converts them to UTC, discarding the original offset. Consequently, UTC‑suffixed strings sort lexicographically in chronological order, while offset‑aware strings do not, and the view server lacks an IANA time‑zone database to resolve names like Europe/Berlin.
The unresolved decision is whether to store all timestamps in UTC and let the application convert user times before querying, or to keep the original offset in the string and add a secondary sort key or collation function, so that a single view query can correctly handle ambiguous local intervals without the application needing to split the request.
Which representation guarantees that a view key range query returns exactly the documents whose timestamps fall inside the user‑specified local interval across DST boundaries? Does preserving the offset and adding a sortable UTC copy provide a simpler, more maintainable solution than relying on the application to split ambiguous queries?
32775 reputation · 27 Feb 2023, 16:13 UTC
Use UTC-only timestamp strings (ISO 8601 ending in Z) as the CouchDB view key. The application must convert user-specified local-time ranges to UTC before issuing the query. Preserving the original offset in a separate document field is safe for auditing or display, but it cannot serve as the primary sort key for range queries.
CouchDB orders view keys lexicographically. ISO 8601 strings that carry different UTC offsets—such as 2026-10-25T02:30:00+02:00 and 2026-10-25T01:30:00Z—do not sort chronologically because the offset portion changes the character sequence. During a DST fall-back transition, an ambiguous local hour like 02:30 can appear twice with different offsets, or the same instant can be written with a Z suffix or a numeric offset. A startkey/endkey range over such strings will miss documents or include the wrong ones.
In CouchDB 3.x, the default JavaScript view server parses strings with new Date(), which normalizes them to UTC internally, but the view index is built from the emitted key string, not from a normalized Date object. The view server also lacks an IANA time-zone database, so it cannot resolve names like Europe/Berlin or determine whether a local timestamp fell before or after a transition.
Emit a single UTC-normalized string as the view key:
function (doc) {
if (doc.occurredAtUtc) {
emit(doc.occurredAtUtc, null);
}
}
Store the original local representation separately if needed:
{
"occurredAtUtc": "2026-10-25T00:30:00Z",
"occurredAtLocal": "2026-10-25T02:30:00+02:00",
"timezone": "Europe/Berlin"
}
The application converts the user's local start and end times to UTC using a robust library (for example, one backed by the IANA database) and passes those UTC strings as startkey and endkey. A single range query then returns exactly the documents whose absolute instants fall inside the requested window.
Adding a secondary sort key or collation function inside the view cannot recover the information that was lost when the offset was discarded, nor can it supply the missing IANA rules. Splitting the query into multiple ranges for each possible offset adds complexity and still requires the application to know the DST rules for the user's region. Converting the boundaries once, before the query, is simpler and keeps the view index small and fast.
startkey and endkey values that correspond to the local boundaries.occurredAtUtc falls within the absolute window and that no document with an offset-aware key was missed.This pattern assumes CouchDB 3.x with the default JavaScript view server. If your deployment uses a custom view server with time-zone data, the calculus could change, but that is uncommon.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.