Skip to content

Commit d1b3e87

Browse files
authored
docs: clarify local-time semantics of anchor dates (#50)
1 parent 6d5256a commit d1b3e87

4 files changed

Lines changed: 42 additions & 2 deletions

File tree

docs/guides/time-zones.mdx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,29 @@ const zoned = eventsInTimeZone(events, "America/New_York");
2929
instant. Keep your source events around for editing and saving.
3030
</Warning>
3131

32+
## Anchor dates are local
33+
34+
The controlled `date` prop, like every `Date` the calendar reads, is
35+
interpreted in the device's local time zone: all date math runs through
36+
date-fns (`startOfWeek`, `startOfMonth`, ...) on the local clock. Construct
37+
anchors as local dates, not UTC instants:
38+
39+
```ts
40+
new Date(2026, 7, 24); // local Aug 24, anchors the week you expect everywhere
41+
new Date("2026-08-24T00:00:00Z"); // UTC instant, still Aug 23 west of UTC
42+
```
43+
44+
On a device west of UTC, that UTC-midnight instant is still the evening of
45+
Aug 23 locally, so a `week` view with `weekStartsOn: 1` builds the week of
46+
Monday Aug 17, a full week before the one intended (Aug 24 is itself a
47+
Monday). The same shift moves a `month` anchor built from
48+
`new Date("2026-08-01T00:00:00Z")` into July.
49+
50+
`timeZone` doesn't change this: it shifts how events display, never how the
51+
`date` prop is read. The dates the calendar hands back (`onChangeDate`,
52+
`onChangeDateRange`, `onPressDay`, ...) are local dates too, so feeding them
53+
straight back into `date` is always safe.
54+
3255
## The now indicator
3356

3457
The current-time line follows the same zone as your events: set `timeZone` on

docs/reference/api.mdx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@ your editor lists the full set with inline docs.
1717
| Prop | Type | Notes |
1818
| --------------- | ------------------------- | ------------------------------------------------- |
1919
| `events` | `CalendarEvent<T>[]` | Your events. The generic `T` is your own data. |
20-
| `date` | `Date` | The controlled anchor date. |
20+
| `date` | `Date` | The controlled anchor date, read in local time. |
2121
| `mode` | `CalendarMode` | `month` `week` `day` `3days` `custom` `schedule`. |
2222
| `numberOfDays` | `number` | Column count for `custom`. |
2323
| `weekStartsOn` | `0–6` | 0 = Sunday, 1 = Monday. |
2424
| `weekdayFormat` | `narrow \| short \| long` | Weekday header width (default `short`). |
2525
| `timeZone` | `string` | Display events in this IANA zone (DST-correct). |
2626

27+
Anchor dates are read in the device's local time zone: construct `date` as a
28+
local date (`new Date(2026, 7, 24)`), not a UTC instant. See
29+
[time zones](/guides/time-zones#anchor-dates-are-local) for the off-by-one-week
30+
pitfall this avoids.
31+
2732
## Navigation
2833

2934
| Prop | Type | Notes |

packages/dom/src/Calendar.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ export interface CalendarProps<T = unknown>
5555
* a day-grouped agenda list, and the others a time grid.
5656
*/
5757
mode?: CalendarMode;
58-
/** Controlled anchor date. Change it (e.g. from your own header) to navigate. */
58+
/**
59+
* Controlled anchor date, read in the device's local time zone; change it
60+
* (e.g. from your own header) to navigate. Construct it as a local date
61+
* (`new Date(2026, 7, 24)`), not a UTC instant:
62+
* `new Date("2026-08-24T00:00:00Z")` is still Aug 23 on devices west of UTC
63+
* and anchors the previous week.
64+
*/
5965
date: Date;
6066
/**
6167
* Fires with the next/previous period's date when the user pages the focused

packages/native/src/components/Calendar.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ export type CalendarSlot = MonthViewSlot | TimeGridSlot | AgendaSlot | YearViewS
6060
export type CalendarProps<T> = SlotStyleProps<CalendarSlot> & {
6161
events: CalendarEvent<T>[];
6262
mode: CalendarMode;
63+
/**
64+
* The controlled anchor date, read in the device's local time zone. Construct
65+
* it as a local date (`new Date(2026, 7, 24)`), not a UTC instant:
66+
* `new Date("2026-08-24T00:00:00Z")` is still Aug 23 on devices west of UTC
67+
* and anchors the previous week.
68+
*/
6369
date: Date;
6470
onChangeDate: (date: Date) => void;
6571
/** Fired alongside `onChangeDate` with the `[start, end]` of the newly-visible range. */

0 commit comments

Comments
 (0)