From aee0d3b5bf3de274849d77b41a41a4711e9eb7f2 Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Wed, 26 Aug 2026 18:31:10 +0200 Subject: [PATCH] docs: clarify local-time semantics of anchor dates --- docs/guides/time-zones.mdx | 23 +++++++++++++++++++++ docs/reference/api.mdx | 7 ++++++- packages/dom/src/Calendar.tsx | 8 ++++++- packages/native/src/components/Calendar.tsx | 6 ++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/guides/time-zones.mdx b/docs/guides/time-zones.mdx index d70892e..e6407ca 100644 --- a/docs/guides/time-zones.mdx +++ b/docs/guides/time-zones.mdx @@ -29,6 +29,29 @@ const zoned = eventsInTimeZone(events, "America/New_York"); instant. Keep your source events around for editing and saving. +## Anchor dates are local + +The controlled `date` prop, like every `Date` the calendar reads, is +interpreted in the device's local time zone: all date math runs through +date-fns (`startOfWeek`, `startOfMonth`, ...) on the local clock. Construct +anchors as local dates, not UTC instants: + +```ts +new Date(2026, 7, 24); // local Aug 24, anchors the week you expect everywhere +new Date("2026-08-24T00:00:00Z"); // UTC instant, still Aug 23 west of UTC +``` + +On a device west of UTC, that UTC-midnight instant is still the evening of +Aug 23 locally, so a `week` view with `weekStartsOn: 1` builds the week of +Monday Aug 17, a full week before the one intended (Aug 24 is itself a +Monday). The same shift moves a `month` anchor built from +`new Date("2026-08-01T00:00:00Z")` into July. + +`timeZone` doesn't change this: it shifts how events display, never how the +`date` prop is read. The dates the calendar hands back (`onChangeDate`, +`onChangeDateRange`, `onPressDay`, ...) are local dates too, so feeding them +straight back into `date` is always safe. + ## The now indicator The current-time line follows the same zone as your events: set `timeZone` on diff --git a/docs/reference/api.mdx b/docs/reference/api.mdx index 6b94d45..c0fa0a2 100644 --- a/docs/reference/api.mdx +++ b/docs/reference/api.mdx @@ -17,13 +17,18 @@ your editor lists the full set with inline docs. | Prop | Type | Notes | | --------------- | ------------------------- | ------------------------------------------------- | | `events` | `CalendarEvent[]` | Your events. The generic `T` is your own data. | -| `date` | `Date` | The controlled anchor date. | +| `date` | `Date` | The controlled anchor date, read in local time. | | `mode` | `CalendarMode` | `month` `week` `day` `3days` `custom` `schedule`. | | `numberOfDays` | `number` | Column count for `custom`. | | `weekStartsOn` | `0–6` | 0 = Sunday, 1 = Monday. | | `weekdayFormat` | `narrow \| short \| long` | Weekday header width (default `short`). | | `timeZone` | `string` | Display events in this IANA zone (DST-correct). | +Anchor dates are read in the device's local time zone: construct `date` as a +local date (`new Date(2026, 7, 24)`), not a UTC instant. See +[time zones](/guides/time-zones#anchor-dates-are-local) for the off-by-one-week +pitfall this avoids. + ## Navigation | Prop | Type | Notes | diff --git a/packages/dom/src/Calendar.tsx b/packages/dom/src/Calendar.tsx index a4e22af..a464100 100644 --- a/packages/dom/src/Calendar.tsx +++ b/packages/dom/src/Calendar.tsx @@ -55,7 +55,13 @@ export interface CalendarProps * a day-grouped agenda list, and the others a time grid. */ mode?: CalendarMode; - /** Controlled anchor date. Change it (e.g. from your own header) to navigate. */ + /** + * Controlled anchor date, read in the device's local time zone; change it + * (e.g. from your own header) to navigate. Construct it as a local date + * (`new Date(2026, 7, 24)`), not a UTC instant: + * `new Date("2026-08-24T00:00:00Z")` is still Aug 23 on devices west of UTC + * and anchors the previous week. + */ date: Date; /** * Fires with the next/previous period's date when the user pages the focused diff --git a/packages/native/src/components/Calendar.tsx b/packages/native/src/components/Calendar.tsx index 848ee3e..f2d3c47 100644 --- a/packages/native/src/components/Calendar.tsx +++ b/packages/native/src/components/Calendar.tsx @@ -60,6 +60,12 @@ export type CalendarSlot = MonthViewSlot | TimeGridSlot | AgendaSlot | YearViewS export type CalendarProps = SlotStyleProps & { events: CalendarEvent[]; mode: CalendarMode; + /** + * The controlled anchor date, read in the device's local time zone. Construct + * it as a local date (`new Date(2026, 7, 24)`), not a UTC instant: + * `new Date("2026-08-24T00:00:00Z")` is still Aug 23 on devices west of UTC + * and anchors the previous week. + */ date: Date; onChangeDate: (date: Date) => void; /** Fired alongside `onChangeDate` with the `[start, end]` of the newly-visible range. */