Date-time range
The canonical event term ("Termín" of a meeting or calendar entry). React <DateTimeRangeField> (packages/ui/src/components/DateTimeRangeField.tsx) composes Date field + two Time fields in .dp-stack / .dp-termin / .dp-timegroup, the switches row .dp-switches ("Celý den" and the caller's extras such as "Opakovat") and the availability line .dp-status. Row order follows Google Calendar (AD, ACRM-136, 7 Sep 2026): first the date and the time, then the switches.
When to use
- Meeting dialog, calendar event, room booking — anything with a start and an end on a clock.
- All-day events: the toggle hides the times and the day row becomes the canonical Date range field (
<DateRangeField>: from–to in one field, one shared calendar, day count) — owner 28 Sep 2026 (acrm M4c): one shape for a range of days in the DS, not two Date fields with their own day arithmetic. A one-day all-day event has from = to. - Overnight events (
allowOvernight): an end earlier than the start is not an error but "přes půlnoc"; the end day is computed (+1).
When not to use
- A due date with an optional time (task) — Date field + Time field in the task panel (
.dp-addtime/.dp-timerow). - A reporting period — Date range.
- Two dates only, no clock — Date range.
Anatomy
.dp-stack: column, gap--sp-3, left-aligned — one gap for every row under the fields, no ad-hoc margins.- Row 1
.dp-termin: timed —<DateField futureBias ariaLabel="Datum">+.dp-timegroup(Time field "Od",.dp-sep, Time field "Do" withgetStart,.dp-durlength); all-day —<DateRangeField futureBias presets={[]} fromLabel="Datum" toLabel="Datum konce">(past-range presets do not fit a future event) +.dp-durday count when longer than one day. The range field swaps the ends itself. Nothing else sits in this row; the range field may shrink (.dp-termin > .dp-fieldset { min-width: 0 }, full row on phone). - Row 2
.dp-switches: the canonical Switch "Celý den" (whenallowAllDay, default true) followed bydayExtrasfrom the caller — the meeting dialog puts "Opakovat" and, once on, its frequency · until · end row here. The row is not rendered when there is nothing to put in it. .dp-dur:--small,--fg-secondary;.overnote in--warning-ink("přes půlnoc", "končí 27. 8.")..dp-status.ok(--positive-ink) /.busy(--critical-ink, × icon): text from theavailabilitycallback, or the built-in overnight error whenallowOvernightis false.- Value contract
{ date, from, to, allDay, toDate }— minutes from midnight, ISO days; the component keepstoDatecomputed so callers composestartsAt/endsAtonly.
Best practices
Do
- Let the start drag the end: moving "od" keeps the duration (code does this); moving the date moves the whole block.
- Provide
availabilityfor meetings and rooms so the status line answers "is it free" in place. - Use
allowOvernightfor meetings, keep it off for rooms where an end before start is a typo.
Don't
- A second date picker asking for the end day of every timed meeting —
allowMultiDaywas removed for that reason. - Duration presets (15 min … 2 h) — removed 6 Sep 2026; the length is written as text after "Do" (
.dp-dur). - Anything but the date and the time in row 1 — switches and recurrence live in
.dp-switches. - Status text as a paragraph — one line, state first.
- A custom toggle for all-day — the canonical control is
<Switch>from@acrm/uiin.dp-switches. The old.dp-alldaycheckbox was removed on 6 Sep 2026 (AD: „předělat na switch“) and the class no longer exists indate-picker.css.
Content
- Length via
fmtDur("45 min", "1 h 30 min"); days viafmtDays("2 dny"). - Overnight note "přes půlnoc"; longer terms "končí 27. 8." (date by
formatDate). - Built-in error: "Konec je před začátkem — schůzka přes půlnoc není povolená."
- Toggle label "Celý den"; field labels "Datum", "Datum konce", "Od", "Do" (sentence case).
- Live region reads "9:00 až 10:30, 1 h 30 min" after every change.
Related
- date-field, time-field — the parts.
- date-range — dates only.
- calendar, picker-panel — the layers the parts open.