Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/guides/time-zones.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ const zoned = eventsInTimeZone(events, "America/New_York");
instant. Keep your source events around for editing and saving.
</Warning>

## 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
Expand Down
7 changes: 6 additions & 1 deletion docs/reference/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ your editor lists the full set with inline docs.
| Prop | Type | Notes |
| --------------- | ------------------------- | ------------------------------------------------- |
| `events` | `CalendarEvent<T>[]` | 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 |
Expand Down
8 changes: 7 additions & 1 deletion packages/dom/src/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ export interface CalendarProps<T = unknown>
* 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
Expand Down
6 changes: 6 additions & 0 deletions packages/native/src/components/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export type CalendarSlot = MonthViewSlot | TimeGridSlot | AgendaSlot | YearViewS
export type CalendarProps<T> = SlotStyleProps<CalendarSlot> & {
events: CalendarEvent<T>[];
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. */
Expand Down