Server‑side vs Client‑side DST offset resolution for ambiguous times in Google Calendar API
0 reputation · 06 Aug 2026, 14:01 UTC
0 reputation · 06 Aug 2026, 14:01 UTC
When an event is scheduled at a local time that falls into a daylight‑saving fallback transition (e.g., 1:30 AM on the first Sunday in November in America/New_York), the Calendar API accepts a dateTime string together with a timeZone ID. The server stores the instant in UTC and preserves the original time‑zone metadata, but the API does not specify which offset is applied if the local time is ambiguous. The Time Zone API can return dstOffset and rawOffset for a UTC timestamp, yet it does not indicate which offset applies to a local time that overlaps.
Client libraries (e.g., JavaScript Intl.DateTimeFormat or Java java.time) rely on the host OS’s time‑zone database. If the server’s database is newer than the client’s, converting the stored UTC back to the original local time can yield a different offset, leading to a one‑hour shift. Additionally, all‑day events are stored as UTC midnight, which can change the local date when daylight saving changes occur.
1. Should the server store an explicit flag indicating which offset was chosen for ambiguous times?
2. What is the recommended client‑side strategy for resolving the correct offset when converting back to local time?
3. How should all‑day events be handled to avoid off‑by‑one‑day bugs across DST transitions?
34775 reputation · 07 Aug 2026, 00:12 UTC
Google Calendar stores the event instant as UTC and keeps the supplied timeZone ID, but it does not expose which of the two possible offsets was chosen when the local time falls into a daylight‑saving fallback. Therefore:
extendedProperties.customOffset) when creating the event.When the server’s tzdata is newer than a client’s, converting the same UTC instant can produce a different offset, shifting the local time by an hour. Storing the offset guarantees that every client, regardless of its tzdata version, displays the intended local time.
POST https://www.googleapis.com/calendar/v3/calendars/primary/events
{
"summary": "Fall back test",
"start": {"dateTime": "2026-11-05T01:30:00", "timeZone": "America/New_York"},
"end": {"dateTime": "2026-11-05T02:30:00", "timeZone": "America/New_York"},
"extendedProperties": {
"private": {"customOffset": "-05:00"}
}
}
The customOffset field records the offset that the server applied (here the earlier offset, UTC‑5).GET https://www.googleapis.com/calendar/v3/calendars/primary/events/{eventId}
The response includes start.dateTime (UTC) and the timeZone ID. If you stored customOffset, read it from extendedProperties.private.customOffset.const utc = new Date(event.start.dateTime);
const tz = event.start.timeZone;
const local = utc.toLocaleString('en-US', { timeZone: tz });
customOffset is present, override the conversion:
const offsetMs = parseOffset(event.extendedProperties.private.customOffset) * 60 * 1000;
const localMs = utc.getTime() + offsetMs;
const localDate = new Date(localMs);
customOffset.
Because all‑day events use only a date field, Google Calendar treats them as spanning midnight UTC of the specified date. The timeZone ID is applied only for display purposes, so DST transitions do not alter the event’s span.
If you cannot guarantee that all clients use the same tzdata version as the server, please confirm:
Answering this will determine whether the custom offset field is necessary.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.