Nowość:Aplikacja Generowana przez AI

API rezerwacji ze strefami czasowymi: Dla agentów AI i custom frontendów

autor: Mateusz Sowa
API rezerwacji ze strefami czasowymi: Dla agentów AI i custom frontendów

Twój agent AI właśnie zarezerwował konsultację na 15:00. Klient jest w Tokio, terapeuta w Berlinie. Które 15:00 miał na myśli agent?

Jeśli odpowiedź nie wynika natychmiast z danych zwróconych przez API, masz błąd strefy czasowej — taki, który po cichu kosztuje firmy tysiące w niestawiennictwach, zgłoszeniach do supportu i utraconym zaufaniu. A gdy autonomiczne agenty AI obsługują rezerwacje bez ludzkiej kontroli, precyzja stref czasowych to nie miły dodatek. To krytyczna infrastruktura.

Tutaj GraphQL pokazuje swoją siłę. W przeciwieństwie do endpointów REST, które zwracają nieprzejrzyste ciągi znaczników czasu i pozostawiają interpretację stref czasowych po stronie wywołującego, dobrze typizowane API GraphQL może kodować semantykę stref czasowych bezpośrednio w schemacie — dając agentom AI jednoznaczne, maszynowo odczytywalne dane czasowe w każdej odpowiedzi.

W Timerise latami pracowaliśmy nad obsługą stref czasowych, która eliminuje tę całą kategorię błędów — dla ludzkich użytkowników i dla agentów AI. Oto jak działa nasze GraphQL API i co to oznacza dla deweloperów budujących własne frontendy lub podłączających autonomicznych agentów.

Główny problem: Czas lokalny to iluzja (i agenci AI nie mogą zgadywać)

Każdy programista uczy się tego prędzej czy później na własnej skórze: czas lokalny nie istnieje w izolacji. „15:00" nie znaczy nic bez punktu odniesienia w postaci strefy czasowej. Człowiek może wywnioskować właściwą strefę z kontekstu. Agent AI nie może — potrzebuje jawnych, ustrukturyzowanych danych. A obsługa stref czasowych jest znacznie bardziej złożona niż dodawanie lub odejmowanie godzin od UTC.

Weź pod uwagę te komplikacje:

  • Zmiana czasu (DST) przesuwa zegary do przodu lub do tyłu, co oznacza, że niektóre godziny lokalne występują dwa razy w roku, a niektóre w ogóle nie istnieją
  • Reguły stref IANA się zmieniają — rządy modyfikują zasady DST, czasem z zaledwie kilkutygodniowym wyprzedzeniem
  • Offsety UTC nie są statyczneEurope/Warsaw to +01:00 zimą i +02:00 latem

Jeśli Twój system rezerwacji przechowuje czasy jako „15:00 CET", już masz problem. CET jest niejednoznaczny — nie mówi, czy obowiązuje czas letni. Dlatego Timerise stosuje zupełnie inne podejście.

Architektura UTC-First w Timerise

Nasze API stosuje ścisły model przechowywania UTC-first. Każdy znacznik czasu w bazie danych jest zapisany jako wartość UTC. Żadnych czasów lokalnych w bazie, żadnej niejednoznaczności, żadnych niespodzianek związanych z DST.

Łączymy to z identyfikatorami stref IANA — standardem branżowym utrzymywanym przez IANA Time Zone Database. Zamiast niejasnych skrótów jak „EST" czy „CET" używamy precyzyjnych identyfikatorów jak America/New_York lub Europe/Warsaw, które kodują pełną historię reguł strefowych danej lokalizacji.

Każdy projekt w Timerise posiada wymagane pole localTimeZone — jedno, programatycznie odpytywalne źródło prawdy, które agenci AI mogą odczytywać:

type Project { localTimeZone: TimeZone! # np. "Europe/Warsaw" now: DateTime! # Bieżący czas UTC nowISO: DateTimeISO! # Bieżący czas w strefie projektu }

To jedno pole steruje generowaniem slotów, formatowaniem wyjścia rezerwacji i wyświetlaniem dla wszystkich usług w danym projekcie. Jedno źródło prawdy, zero zgadywania. Agent AI może odpytać localTimeZone raz i używać go do poprawnej interpretacji każdego znacznika czasu zwracanego przez projekt.

Dwa typy DateTime: Maszynowy i czytelny dla ludzi

API Timerise udostępnia dwa typy skalarne, które rozwiązują problem „które 15:00?". To rozróżnienie czyni API wyjątkowo przyjaznym agentom AI — agent zawsze wie, którego pola użyć do logiki, a którego do wyświetlania:

SkalarFormatPrzykładZastosowanie
DateTimeUTC ISO 86012026-02-16T19:43:29.000ZArytmetyka czasowa, przechowywanie, porównania
DateTimeISOISO 8601 z offsetem2026-02-16T20:43:29+01:00Czytelne wyświetlanie dla ludzi

DateTime to format przyjazny maszynom. Zawsze kończy się na Z (czas Zulu = UTC). Agenci AI powinni używać tego pola do wszystkich obliczeń czasowych — porównań, sortowania, wykrywania konfliktów i logiki harmonogramowania.

DateTimeISO to format przyjazny użytkownikom. Pokazuje czas lokalny z offsetem UTC, więc użytkownik w Warszawie widzi 20:43:29+01:00 — od razu jasne, bez potrzeby przeliczania w głowie. Gdy agent AI musi prezentować czasy użytkownikom końcowym, DateTimeISO dostarcza gotową do wyświetlenia wartość z prawidłowym lokalnym offsetem.

Każdy slot w systemie udostępnia oba:

type Slot { dateTimeFrom: DateTime! # "2026-02-16T19:43:29.000Z" dateTimeFromISO: DateTimeISO! # "2026-02-16T20:43:29+01:00" dateTimeTo: DateTime! dateTimeToISO: DateTimeISO! }

Dla deweloperów budujących własne frontendy zasada jest prosta: używaj dateTimeFrom / dateTimeTo do arytmetyki czasowej, a dateTimeFromISO / dateTimeToISO do wyświetlania użytkownikom.

Automatyczne wykrywanie strefy użytkownika w custom frontendach

Kiedy budujesz własną stronę rezerwacyjną na Timerise, Twoi użytkownicy mogą znajdować się w innej strefie czasowej niż usługodawca. Oto jak obsłużyć to elegancko.

Wykrywanie po stronie przeglądarki

Nowoczesne przeglądarki udostępniają strefę czasową użytkownika przez Intl API (Application Programming Interface):

const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; // Zwraca identyfikator IANA, np. "America/New_York"

To zwraca prawidłowy identyfikator IANA — dokładnie taki format, jakiego oczekuje Timerise. Możesz go przekazać bezpośrednio do API przy tworzeniu rezerwacji:

mutation CreateBooking { bookingCreate( serviceId: "srv_12345" slots: ["slot_abc"] timeZone: "America/New_York" # z Intl API ) { bookingId dateTimeFrom dateTimeFromISO } }

Parametr timeZone jest zapisywany w dokumencie rezerwacji. Później, gdy użytkownik przegląda potwierdzenie, pole dateTimeFromISO automatycznie formatuje czas w jego strefie czasowej z prawidłowym offsetem.

Przeliczanie czasów wyświetlania dla użytkowników

Co jeśli Twój frontend musi pokazywać czasy slotów w lokalnej strefie użytkownika, a nie usługodawcy? API zwraca zarówno UTC, jak i czas lokalny dostawcy, dając pełną elastyczność.

Opcja A — Pozwól API pracować. Pobierz sloty normalnie i użyj pól DateTime (UTC). Następnie sformatuj je po stronie klienta z wykrytą strefą:

const slotUTC = "2026-02-16T19:43:29.000Z"; const userTZ = Intl.DateTimeFormat().resolvedOptions().timeZone; const localTime = new Date(slotUTC).toLocaleString("pl-PL", { timeZone: userTZ, hour: "2-digit", minute: "2-digit", hour12: false, }); // "14:43" dla America/New_York (UTC-5)

Opcja B — Pokaż obie perspektywy. Wyświetl czas lokalny dostawcy (dateTimeFromISO) obok czasu lokalnego użytkownika. To buduje zaufanie przy rezerwacjach między strefami:

Czas sesji: 20:43 Warszawa (14:43 Twój czas)

Oba podejścia działają, ponieważ API daje Ci surowe dane UTC i sformatowany czas lokalny dostawcy. Ty decydujesz, jak to zaprezentować.

Generowanie slotów: Gdzie strefy czasowe stają się trudne

Za kulisami silnik generowania slotów Timerise rozwiązuje najtrudniejsze problemy strefowe, dzięki czemu Ty nie musisz.

Kiedy usługodawca ustawia swoją dostępność jako „poniedziałek–piątek, 9:00–17:00", ma na myśli czas lokalny. Ale system przechowuje wszystko w UTC. Konwersja musi uwzględniać przejścia DST, gdzie offset zmienia się w trakcie harmonogramu.

Timerise rozwiązuje to za pomocą biblioteki date-fns-tz i trzech kluczowych funkcji:

  • fromZonedTime(localDate, timeZone) — konwertuje czas zegarowy na UTC
  • toZonedTime(utcDate, timeZone) — konwertuje UTC na czas zegarowy
  • formatInTimeZone(utcDate, timeZone, format) — formatuje datę UTC do wyświetlenia w dowolnej strefie

Pipeline generowania działa tak:

  1. Harmonogram dostawcy (czasy lokalne) → konwersja do granic UTC przez fromZonedTime
  2. Wykrywanie nakładania slotów → czysta arytmetyka milisekund UTC, bez konwersji stref
  3. Filtrowanie godzin pracy → toZonedTime przelicza z powrotem na czas lokalny do porównań godzin
  4. Asemblacja wyjścia → zarówno pola DateTime (UTC) jak i DateTimeISO (z offsetem)

To oznacza, że slot o 9:00 w Europe/Warsaw staje się prawidłowo 08:00:00Z zimą (+01:00) i 07:00:00Z latem (+02:00). Generowanie slotów obsługuje to automatycznie przez granice DST — bez ręcznej interwencji.

Praktyczne wskazówki dla deweloperów frontend

Budujesz własny frontend na Timerise? Pamiętaj o tych zasadach:

1. Zawsze wysyłaj UTC dla wejść DateTime

Skalar DateTime parsuje dane wejściowe jako UTC. Nie wysyłaj czasów lokalnych bez sufiksu Z — zostaną błędnie zinterpretowane jako UTC:

✅ Poprawnie: "2026-02-16T19:43:29.000Z" ❌ Źle: "2026-02-16T20:43:29" (traktowane jako UTC, przesunięcie o 1 godzinę)

2. Wiedz, kiedy użyć wejść DateTimeISO vs DateTime

Pola wyjściowe DateTimeISO są obliczane przy każdym zapytaniu z przechowywanej wartości UTC i strefy rezerwacji. Ale DateTimeISO jest też akceptowany jako dane wejściowebookingCreate, bookingReschedule, bookings i services obsługują parametry dateTimeISOFrom / dateTimeISOTo. Używaj wejść DateTimeISO, gdy masz już czas lokalny z offsetem (np. z kalendarza użytkownika). Używaj wejść DateTime (UTC), gdy wykonujesz arytmetykę czasową lub gdy już przekonwertowałeś na UTC.

3. Obsługuj brak strefy czasowej z wdziękiem

Starsze rekordy rezerwacji mogą nie mieć pola timeZone, co powoduje, że dateTimeFromISO zwraca null. Zawsze miej zapasowe rozwiązanie z polem UTC dateTimeFrom:

const displayTime = booking.dateTimeFromISO ?? new Date(booking.dateTimeFrom).toLocaleString();

4. Wykryj strefę raz, używaj wszędzie

Wywołaj Intl.DateTimeFormat().resolvedOptions().timeZone raz przy ładowaniu strony i zapisz wynik. Przekazuj ten sam identyfikator IANA do każdej mutacji bookingCreate lub bookingReschedule. Spójność zapobiega rozbieżnym rekordom stref. Dla agentów AI strefa czasowa powinna być pobrana z profilu użytkownika lub kontekstu sesji i przekazywana konsekwentnie w każdym wywołaniu API.

5. Pamiętaj: Dni DST nie zawsze trwają 24 godziny

Jeśli budujesz widok dzienny kalendarza, nie zakładaj, że 24 * 60 * 60 * 1000 milisekund to jeden dzień. Podczas przejść DST dzień lokalny może trwać 23 lub 25 godzin. Używaj funkcji bibliotecznych (jak date-fns) do arytmetyki dat zamiast surowych obliczeń milisekundowych.

DateTimeISO jako dane wejściowe: Wysyłaj czasy lokalne bezpośrednio

Poza byciem skalarem wyjściowym, DateTimeISO jest akceptowany jako typ wejściowy dla zapytań i mutacji. Oznacza to, że możesz wysyłać czasy lokalne z ich offsetem UTC bezpośrednio — API parsuje offset i konwertuje wewnętrznie do UTC.

To znacząca poprawa dla agentów AI i aplikacji opartych na LLM. Zamiast konwertować czasy lokalne na UTC przed każdym wywołaniem API, agent może przekazać czas lokalny użytkownika bez zmian z offsetem — mniej logiki konwersji, eliminacja klasy błędów, prostszy i bardziej niezawodny kod agenta.

Następujące zapytania i mutacje akceptują parametry dateTimeISOFrom / dateTimeISOTo:

  • Zapytania: bookings i services — filtrowanie wyników po zakresie czasu lokalnego
  • Mutacje: bookingCreate i bookingReschedule — określanie czasu rezerwacji w czasie lokalnym
mutation CreateBooking { bookingCreate( serviceId: "srv_12345" dateTimeISOFrom: "2026-03-15T09:00:00+01:00" dateTimeISOTo: "2026-03-15T10:00:00+01:00" ) { bookingId status } }
query GetBookings { bookings( dateTimeISOFrom: "2026-03-15T00:00:00+01:00" dateTimeISOTo: "2026-03-16T00:00:00+01:00" ) { bookingId dateTimeFrom dateTimeFromISO # czas lokalny z offsetem UTC (np. "2026-03-15T09:00:00+01:00") } }

Bez ręcznej konwersji UTC. Bez arytmetyki offsetów. API to obsługuje.

Dlaczego GraphQL + pełna obsługa stref to najlepszy stack dla agentów AI

Błędy stref czasowych to nie przypadki brzegowe — to zabójcy przychodów. Każdy błędny czas spotkania oznacza:

  • Niestawiennictwo zdezorientowanych klientów
  • Zgłoszenia do supportu od sfrustrowanych użytkowników
  • Podwójne rezerwacje, gdy sloty nakładają się przez przejścia DST
  • Odpowiedzialność prawna w planowaniu medycznym lub prawnym

Gdy agenci AI obsługują rezerwacje autonomicznie, stawka jest jeszcze wyższa. Nie ma człowieka w pętli, który złapie błąd strefy zanim dotrze do klienta. API musi być poprawne z założenia.

Tutaj kombinacja GraphQL i pełnej obsługi stref czasowych Timerise tworzy unikatowo wydajny stack dla autonomicznych agentów:

  1. Bezpieczeństwo typów na poziomie schematu — skalary DateTime, DateTimeISO i TimeZone uniemożliwiają agentowi wysłanie błędnych danych czasowych. Schema to kontrakt.
  2. Introspekcja — agent AI może odpytać sam schemat o dostępne pola i typy. Bez parsowania dokumentacji, bez ryzyka halucynacji.
  3. Precyzyjne pobieranie danych — agent żąda tylko potrzebnych pól czasowych. Bez over-fetchingu, bez marnowania tokenów.
  4. Jednoznaczna semantyka stref — każda odpowiedź zawiera zarówno UTC, jak i czasy z offsetem. Agent zawsze dokładnie wie, jaką strefę reprezentuje wartość.
  5. Wejścia DateTimeISO — agenci wysyłają czasy lokalne bezpośrednio, eliminując konwersję UTC po stronie klienta.

REST API pozostawia interpretację stref czasowych wywołującemu. GraphQL API z typizowanymi skalarami stref czasowych sprawia, że nie da się źle zinterpretować znacznika czasu. Dla agentów AI działających na skalę w wielu strefach czasowych to nie wygoda — to wymóg.

API Timerise przejmuje złożoność. Twój frontend — lub Twój agent AI — przejmuje doświadczenie. Twoi użytkownicy widzą właściwy czas, za każdym razem.


Gotowy budować rezerwacje świadome stref czasowych z agentami AI?

Odkryj dokumentację Timerise API →

Czytaj: GraphQL — idealny backend dla agentów AI →

Testuj zapytania GraphQL na żywo →

Zarejestruj się i zacznij budować za darmo →

<br>

Mateusz Sowa