# Shadcn Date Time Picker mit Zeitzonen und Presets

> Ein shadcn Date Time Picker in einem Feld: Kalender, freie Zeitslots, Presets und Zeitzonen-Label, ein Zonen-Select daneben und ein Bottom Sheet am Handy.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 5. Nov. 2026
- Kategorie: [Komponenten-Guides](https://wingo-ui.com/de/blog/category/components)
- Lesezeit: 9 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/shadcn-date-time-picker
- Englische Fassung: https://wingo-ui.com/blog/shadcn-date-time-picker

## Kurz gesagt

shadcn/ui hat keinen Date Time Picker: Die Doku kombiniert den Calendar in einem Popover mit einem separaten input type="time", also führst du die beiden Werte selbst zusammen und kümmerst dich auch um die Zeitzonen. Ein vollständiger shadcn Date Time Picker hält einen einzigen Date-Wert, zeigt neben dem Kalender die freien Zeitslots des gewählten Tages, benennt die Zeitzone und öffnet am Handy ein Bottom Sheet. Der Date Time Picker von Wingo UI erledigt das, und das Timezone Select daneben lässt die Zone wechseln.

Du brauchst einen shadcn Date Time Picker für eine Buchung, eine Erinnerung oder einen geplanten Versand: ein Feld, in dem jemand Tag und Uhrzeit wählt, sieht, in welcher Zeitzone das gilt, und einen Wert bekommt, den dein Server ohne Raten speichern kann. shadcn/ui gibt dir einen Calendar und ein Input, den Rest verdrahtest du selbst. Dieser Guide zeigt, was diese Verdrahtung lösen muss, welche Props im [Date Time Picker](https://wingo-ui.com/components/date-time-picker) von Wingo UI zählen, wie du ihn mit einem [Timezone Select](https://wingo-ui.com/components/timezone-select) kombinierst und was aus beiden am Handy wird.

## Hat shadcn/ui einen Date Time Picker?

Nein. Stand November 2026 enthält die [Doku zum Date Picker](https://ui.shadcn.com/docs/components/date-picker) von shadcn/ui ein Beispiel „Time Picker“, und sein [Quellcode](https://github.com/shadcn-ui/ui/blob/main/apps/v4/examples/radix/date-picker-time.tsx) zeigt das Muster: der Calendar von shadcn in einem Popover für den Tag, daneben ein schlichtes `<Input type="time" step="1" defaultValue="10:30:00" />`. Der Tag liegt als `Date` im React-State, die Uhrzeit bleibt im unkontrollierten Input, und nichts verbindet die beiden. Als Ausgangspunkt taugt das, aber vier Aufgaben bleiben bei dir:

- **Ein Wert.** Du hast ein `Date` um lokale Mitternacht und einen String `"10:30:00"`. Irgendwer muss beides zusammenführen, und zwar in der richtigen Zeitzone.
- **Zeitzonen.** Überall wird die Zone des Browsers angenommen. Unter dem Calendar steckt react-day-picker, dessen [Prop timeZone](https://daypicker.dev/localization/setting-time-zone) die Tage in einer IANA-Zone darstellt, aber keine Uhrzeit auswählt.
- **Verfügbarkeit.** Ein natives Zeitfeld nimmt jede Minute an. Es kann 10:00 nicht als schon vergeben durchstreichen.
- **Smartphones.** Das Popover hängt an einem kleinen Trigger, und das native Zeitfeld sieht in jedem Browser anders aus.

Community-Repos für einen shadcn Datetime Picker schließen einen Teil der Lücke. Stand 5. November 2026 hat [rudrodip/shadcn-date-time-picker](https://github.com/rudrodip/shadcn-date-time-picker) 310 GitHub-Sterne, eine MIT-Lizenz und den letzten Push im Mai 2025. Es bringt Varianten für 12 und 24 Stunden mit, die Spalten mit Buttons für Stunden und Minuten neben den Kalender in ein Popover setzen, dazu Beispiele mit react-hook-form und zod; Zeitzonen oder ein Layout fürs Handy erwähnt das README nicht. [maliksidk19/shadcn-datetime-picker](https://github.com/maliksidk19/shadcn-datetime-picker) hat 281 Sterne und den letzten Push im Juli 2026, und sein README listet einiges auf: einen Kalender neben einer scrollbaren Zeitliste in einem Popover, eine Zeitzonen-Auswahl mit Offsets, Intervalle von 15, 30 oder 60 Minuten mit minimaler und maximaler Uhrzeit sowie einen Drawer unter 768px. Es ist kostenlos (laut README MIT) und reicht für viele Formulare. Seine Grenze ist die Verfügbarkeit pro Tag: Das README behandelt feste Intervalle, Zeitgrenzen und gesperrte Tage, aber nichts, das einen einzelnen Slot als belegt markiert.

| Stand 5. Nov. 2026 | Beispiel von shadcn/ui | Repo von rudrodip | Repo von maliksidk19 | Date Time Picker von Wingo UI |
|---|---|---|---|---|
| Wert | getrennt: `Date` und Zeit-String | ein `Date` | ein `Date` | ein `Date`, abgeschickt als ISO |
| Zeiteingabe | natives `type="time"` | Spalten für Stunden und Minuten | scrollbare Slot-Liste | Slot-Liste aus deiner Verfügbarkeit, belegte Slots durchgestrichen |
| Zeitzone | Zone des Browsers | nicht erwähnt | Zeitzonen-Auswahl | IANA-`timeZone`, Label mit Offset, optional umschaltbar |
| Presets | nein | nicht erwähnt | nicht erwähnt | In 1 hour, Tomorrow 9:00, Monday 9:00 oder deine eigenen |
| Handy | dasselbe Popover | dasselbe Popover | Drawer unter 768px | Bottom Sheet mit Chip-Leisten in 44px |
| Preis | kostenlos, MIT | kostenlos, MIT | kostenlos, MIT (README) | Pro |

## Was sollte ein React Date Time Picker können?

Ein React Date Time Picker ist fertig, wenn die Person die Frage „wann?“ an einer Stelle beantworten kann. In der Praxis heißt das:

1. **Ein Kalender und die freien Uhrzeiten des gewählten Tages nebeneinander**, so wie auf Buchungsseiten.
2. **Ein absoluter Wert**: ein `Date`, das überall denselben Moment meint, nie ein lokales Datum plus eine lose Uhrzeit.
3. **Eine sichtbare Zeitzone.** „2:30 PM“ sagt nichts in einem Team, das zwischen New York und Berlin verteilt ist. Das Label gehört ins Panel, mit dem UTC-Offset für genau dieses Datum, denn die Zeitumstellung verschiebt ihn.
4. **Abkürzungen.** Die meisten Erinnerungen heißen „in einer Stunde“ oder „morgen früh“.
5. **Ein Layout für Daumen.** Unter 768px passt kein Popover mit zwei Spalten. Ein Bottom Sheet mit großen Chips schon.

## Welche Props zählen im Date Time Picker von Wingo UI?

Die meisten Formulare brauchen nur den Wert, `timeZone`, das Slot-Raster oder `getTimeSlots`, die Grenzen, `presets` und `name`. Installier ihn mit `npx wingo-ui@latest add date-time-picker`. Die CLI kopiert `components/ui/date-time-picker.tsx` in dein Projekt und holt den [Calendar](https://wingo-ui.com/components/calendar), Select, Drawer, Field sowie die Helfer für Datum und Motion dazu, die er importiert.

Der Wert ist ein `Date | null`, kontrolliert über `value` und `onValueChange` oder unkontrolliert über `defaultValue`. Diese Props wirst du brauchen:

- `timeZone`: die IANA-Zone, in der die Uhrzeiten gewählt werden (`"America/New_York"`). Kalender und Slots zeigen die Uhr dieser Zone, und Uhrzeiten, die eine Zeitumstellung überspringt, sind gesperrt. Ohne das Prop gilt die Zone des Geräts.
- `minuteStep`, `startTime`, `endTime`: das Standardraster der Slots, 15 Minuten von `"00:00"` bis `"23:59"`. Für Geschäftszeiten nimm `startTime="09:00"` und `endTime="17:00"`.
- `getTimeSlots`: Verfügbarkeit pro Tag, die das Raster ersetzt. Gib `"HH:mm"`-Strings oder Objekte `{ time, disabled, label }` zurück, oder ein Promise davon. Die Antworten werden pro Funktion und Tag gecacht, also definier die Funktion außerhalb der Komponente.
- `disablePast`, `min`, `max`, `disabledDays`: Grenzen. `disabledDays={{ dayOfWeek: [0, 6] }}` sperrt die Wochenenden.
- `presets`: `true` für In 1 hour (auf den Schritt aufgerundet), Tomorrow 9:00 und Monday 9:00, oder deine eigene Liste aus `{ label, value }`.
- `showTimeZone` und `timeZones`: Das Zonen-Label im Footer ist standardmäßig an; ein Array in `timeZones` macht daraus ein Select.
- `name`: schickt `value.toISOString()` über ein verstecktes Input ab, sodass ein einfaches Formular oder eine Server Action einen UTC-String bekommt.

Öffne unten das Feld, probier ein Preset und wähl dann Tag und Uhrzeit. Belegte Slots sind durchgestrichen, und der Footer nennt die Zone.

> Live-Demo (Date Time Picker): Klick ins Feld, probier einen Preset-Chip und wähl dann einen Werktag und einen freien Slot: Belegte Zeiten sind durchgestrichen, der Footer zeigt die Zeitzone, und in Handybreite öffnet sich das Panel als Bottom Sheet. Probier sie unter [Date Time Picker](https://wingo-ui.com/components/date-time-picker) aus und installier sie mit `npx wingo-ui@latest add date-time-picker`.

Tastatur: Die Pfeiltasten springen um einen Tag oder eine Woche, Tab wechselt in die Zeitliste, `14` springt auf 2:00 PM, Enter wählt aus und schließt, Escape gibt den Fokus ans Feld zurück.

## Wie ergänze ich daneben eine Auswahl für die Zeitzone?

Setz ein React Timezone Select über den Picker und gib seinen Wert an `timeZone` weiter. Das brauchst du, wenn die Zone eine Entscheidung der Person ist, etwa wenn ein Host einen Call mit einem Kunden im Ausland plant. Das [Timezone Select](https://wingo-ui.com/components/timezone-select) von Wingo UI listet jede Zone, die der Browser kennt, gruppiert nach Region und mit aktuellen UTC-Offsets. Du kannst nach Stadt („tokyo“), Abkürzung („CET“) oder Offset („+5:30“) suchen, und die erste Zeile wählt deine eigene Zone. Installier es mit `npx wingo-ui@latest add timezone-select`.

> Live-Demo (Timezone Select): Fokussier das Feld und tipp tokyo, EST oder +2: Die Liste filtert beim Tippen, jede Zeile zeigt Offset und Ortszeit, und die erste Zeile wählt deine eigene Zone. Probier sie unter [Timezone Select](https://wingo-ui.com/components/timezone-select) aus und installier sie mit `npx wingo-ui@latest add timezone-select`.

Der Date Time Picker folgt seinem Prop `timeZone`, eine neue Zone zeichnet Kalender und Slots also in der Uhr dieser Zone neu. Auch das Timezone Select nimmt ein `name`, damit die Zonen-ID mit dem Formular mitgeschickt wird.

## Wie baue ich ein Buchungsfeld mit Zeitzone?

Hier ist ein vollständiger React Date Time Picker mit Zeitzone: ein Client-Formular mit dem Zonen-Select über dem Picker, Verfügbarkeit aus einer stabilen Funktion und eine Server Action, die den ISO-String und die Zonen-ID bekommt.

```tsx
"use client";

import { useState } from "react";
import { Globe } from "lucide-react";
import { Button } from "@/components/ui/button";
import { DateTimePicker, buildTimeSlots, type DateTimeSlot } from "@/components/ui/date-time-picker";
import { TimeZoneSelect } from "@/components/ui/timezone-select";
import { bookCall } from "./actions";

// calls mit 30 minuten an werktagen, der letzte endet um 17 uhr; um 12:00 ist mittagspause im team
function freeSlots(day: Date): DateTimeSlot[] {
  if (day.getDay() === 0 || day.getDay() === 6) return [];
  return buildTimeSlots({ step: 30, start: "09:00", end: "16:30" }).map((time) => ({
    time,
    disabled: time === "12:00",
  }));
}

export function BookCallForm() {
  const [timeZone, setTimeZone] = useState("America/New_York");
  const [startsAt, setStartsAt] = useState<Date | null>(null);

  return (
    <form action={bookCall} className="flex max-w-sm flex-col gap-4">
      <TimeZoneSelect
        label="Zeitzone"
        leftIcon={<Globe />}
        value={timeZone}
        onValueChange={setTimeZone}
        suggested={["America/New_York", "America/Chicago", "America/Los_Angeles", "Europe/London"]}
        name="time_zone"
      />
      <DateTimePicker
        label="Call mit Emma Carter"
        description="30 Minuten im Videocall."
        value={startsAt}
        onValueChange={setStartsAt}
        getTimeSlots={freeSlots}
        disabledDays={{ dayOfWeek: [0, 6] }}
        disablePast
        presets
        timeZone={timeZone}
        locale="en-US"
        required
        name="starts_at"
      />
      <Button type="submit" tone="brand" disabled={!startsAt}>
        Call buchen
      </Button>
    </form>
  );
}
```

```ts
// actions.ts
"use server";

function isTimeZone(zone: string) {
  try {
    new Intl.DateTimeFormat("en-US", { timeZone: zone });
    return true;
  } catch {
    return false;
  }
}

export async function bookCall(formData: FormData) {
  const startsAt = new Date(String(formData.get("starts_at")));
  const timeZone = String(formData.get("time_zone"));
  if (Number.isNaN(startsAt.getTime())) throw new Error("Wähl ein Datum und eine Uhrzeit");
  if (!isTimeZone(timeZone)) throw new Error("Wähl eine Zeitzone");
  // prüfen, ob der slot noch frei ist, dann startsAt als utc und timeZone daneben speichern
}
```

`getTimeSlots` bekommt ein `Date` um lokale Mitternacht für den Kalendertag in der gewählten Zone, also ist `day.getDay()` der Wochentag, den die Person sieht. Lass die Funktion auf Modulebene oder pack sie in `useMemo`, denn der Picker cacht ihre Antworten pro Funktion und Tag. Das letzte Wort zur Verfügbarkeit hat nie der Client: Zwei Gäste können denselben freien Slot öffnen, deshalb prüft die Action ihn vor dem Speichern noch einmal.

### Soll die Uhrzeit gleich bleiben, wenn sich die Zone ändert?

Der Picker behält den Zeitpunkt: Ein Call um 2:30 PM in New York steht nach dem Wechsel auf Los Angeles bei 11:30 AM. Das passt für „wann findet dieses Meeting für mich statt“. Für „9 Uhr, egal wo ich bin“ behältst du die Uhrzeit und verschiebst den Zeitpunkt, mit den Helfern, die die Datei exportiert:

```ts
import { getZonedParts, zonedTimeToDate } from "@/components/ui/date-time-picker";

function keepWallTime(value: Date, from: string, to: string) {
  const { date, time } = getZonedParts(value, from);
  return zonedTimeToDate(date, time, to);
}
```

Ruf sie im `onValueChange` des Selects auf, bevor du die Zone aktualisierst. `zonedTimeToDate` berücksichtigt die Zeitumstellung: Gibt es eine Stunde zweimal, nimmt sie das erste Vorkommen, und `formatTimeZoneLabel(zone, date, "en-US")` gibt die Zone mit dem Offset für dieses Datum aus („Eastern Time (UTC−04:00)“ im Juli, „Eastern Time (UTC−05:00)“ im Dezember).

## Wie sieht er am Handy aus?

Mit `responsive` (standardmäßig an) öffnet das Feld unter 768px ein Bottom Sheet statt eines Popovers. Der Kalender nimmt die volle Breite ein, Presets und Uhrzeiten werden zu horizontalen Leisten aus 44px großen Chips, und die gewählte Uhrzeit scrollt in die Mitte. Die Auswahl bleibt ein Entwurf, bis der große Button Done sie übernimmt; wer das Sheet wegzieht, behält also den alten Wert. Das Timezone Select macht auf seiner Seite dasselbe: Ein Tipp öffnet ein Such-Sheet in voller Höhe mit 48px hohen Zeilen und einem Button Cancel. Wir haben uns für ein Sheet entschieden, weil ein Popover an einem Feld weit unten auf dem Screen unter der Tastatur aufgeht oder unter dem Daumen, der es angetippt hat. Der [Guide zum Responsive Dialog](https://wingo-ui.com/de/blog/shadcn-responsive-dialog-on-mobile) erklärt denselben Kompromiss für Dialoge.

Das Prop `inline` rendert das Panel ohne Trigger direkt in die Seite, passend für eine Buchungsseite. Unter 640px legt es die Uhrzeiten in ein Raster unter dem Kalender.

> Live-Demo (Date Time Picker): Das Inline-Panel: Wähl einen Werktag, dann eine Uhrzeit. Zieh den Rahmen schmaler als 640px, und die Uhrzeiten wandern in ein Raster unter dem Kalender. Probier sie unter [Date Time Picker](https://wingo-ui.com/components/date-time-picker) aus und installier sie mit `npx wingo-ui@latest add date-time-picker`.

Die [Vorlage Demo Booking Page](https://wingo-ui.com/templates/demo-booking-page) zeigt einen kompletten Screen zum Buchen einer Demo, aufgebaut um einen Calendar und einen Schritt für die Uhrzeit, falls du neben dem Feld auch die Seite willst.

## Wann nehme ich einen anderen Picker?

- Nur eine Uhrzeit, etwa Öffnungszeiten oder eine tägliche Erinnerung: Der [Time Picker](https://wingo-ui.com/components/time-picker) speichert `"HH:mm"` und nimmt getippte Eingaben wie „2p“ an. Der [Guide zum React Time Picker](https://wingo-ui.com/de/blog/react-time-picker) behandelt ihn.
- Ein Start- und ein Enddatum: der [Guide zum React Date Range Picker](https://wingo-ui.com/de/blog/react-date-range-picker).
- Nur ein Tag, mit Tippen: der [Date Picker](https://wingo-ui.com/components/date-picker).
- Ein Kalender mit bestehenden Terminen, die man per Drag verschiebt: der [Guide zum React-Kalender mit Events](https://wingo-ui.com/de/blog/react-calendar-component-with-events).

## Was sind die typischen Stolperfallen?

- **Das Date auf dem Server bauen.** `new Date("2026-11-12 14:30")` nimmt die Zone des Servers. Rechne stattdessen in der Zone der Person um.
- **Lokale Zeit ohne Zone speichern.** Speicher den UTC-Zeitpunkt und die IANA-ID. Ein Offset wie `-05:00` reicht nicht, denn er ändert sich im März.
- **Ein neues `getTimeSlots` bei jedem Render** setzt den Cache zurück und lädt neu.
- **Hydration.** „Jetzt“ ist auf dem Server und im Browser nicht dasselbe. Der Picker liest die Uhr erst nach der Hydration, Presets und `disablePast` stellen sich also im Client ein; in Tests und Screenshots gibst du `now` mit.

## Wie bekomme ich ihn?

Führ `npx wingo-ui@latest add date-time-picker timezone-select` aus, und die CLI kopiert beide mit allem, was sie importieren, nach `components/ui`. Es sind Pro-Komponenten: $8 im Monat, $80 im Jahr oder $150 einmalig ([Preise](https://wingo-ui.com/de/pricing)). Öffne die [Doku zum Date Time Picker](https://wingo-ui.com/components/date-time-picker), um vorher jedes Prop im Playground auszuprobieren. Weitere Deep Dives zu einzelnen Komponenten findest du in der [Kategorie Komponenten-Guides](https://wingo-ui.com/de/blog/category/components), und der [Guide zu React-Formularkomponenten](https://wingo-ui.com/de/blog/react-form-components-guide) zeigt, wie die Felder zusammenspielen.

## Komponenten in diesem Artikel

- [Date Time Picker](https://wingo-ui.com/components/date-time-picker) (Pro): A React date time picker: a calendar beside a column of free time slots, presets and a time zone label in one field, a sheet on phones. Installation: `npx wingo-ui@latest add date-time-picker`
- [Timezone Select](https://wingo-ui.com/components/timezone-select) (Pro): A searchable time zone picker with live UTC offsets, optional local times, region groups and a one-tap Use my time zone row. Installation: `npx wingo-ui@latest add timezone-select`
- [Calendar](https://wingo-ui.com/components/calendar) (Pro): A React calendar to pick one day, several days or a range, with disabled days, event dots, several months and a quick month / year jump. Installation: `npx wingo-ui@latest add calendar`
- [Time Picker](https://wingo-ui.com/components/time-picker) (Pro): A React time picker to type a time or pick it from columns, with 12 / 24 hours by locale, minute steps, limits and wheels on phones. Installation: `npx wingo-ui@latest add time-picker`

## Häufige Fragen

### Hat shadcn/ui einen Date Time Picker?

Stand November 2026 nicht. Die Doku zum Date Picker enthält ein Beispiel „Time Picker“, das ein Calendar-Popover neben ein separates input type="time" setzt und Datum und Uhrzeit in zwei getrennten States hält.

### Wie mache ich in React aus Datum und Uhrzeit ein einziges Date?

Erzeug den Zeitpunkt in der Zeitzone, die die Person meint, nicht in der des Servers: Nimm den Tag als "YYYY-MM-DD" und die Uhrzeit als "HH:mm" und rechne beides zusammen um. Der Helfer zonedTimeToDate("2026-11-12", "14:30", "America/New_York") von Wingo UI liefert das absolute Date und berücksichtigt die Zeitumstellung.

### Was sollte ein React Date Time Picker mit Zeitzone an den Server schicken?

Einen ISO-String in UTC für den Zeitpunkt und daneben die IANA-Zonen-ID, etwa 2026-11-12T19:30:00.000Z und America/New_York. Der ISO-String ist eindeutig, und mit der Zone kannst du die Uhrzeit später so anzeigen, wie die Person sie gewählt hat.

### Was passiert mit der gewählten Uhrzeit, wenn sich die Zeitzone ändert?

Im Date Time Picker von Wingo UI bleibt der Zeitpunkt gleich und die angezeigte Uhrzeit verschiebt sich: Aus einem Call um 2:30 PM in New York wird in Los Angeles 11:30 AM. Willst du 2:30 PM behalten und stattdessen den Zeitpunkt verschieben, rechne ihn mit getZonedParts und zonedTimeToDate um.

### Ist der Date Time Picker von Wingo UI kostenlos?

Nein. Date Time Picker, Timezone Select, Calendar und Time Picker sind Pro-Komponenten; Pro kostet $8 im Monat, $80 im Jahr oder $150 einmalig. Button, Field, Select und Drawer, auf denen sie aufbauen, sind kostenlos.

---

Quelle: https://wingo-ui.com/de/blog/shadcn-date-time-picker
