Strefy czasowe i znaczniki czasu
Przechowywanie czasu UTC, konwersja stref oraz pułapki dotyczące znaczników czasu poruszane przez rekruterów.
Strefy czasowe i znaczniki czasu to bezpłatna lekcja Coding Interview Prep na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Coding Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.
Dlaczego strefy czasowe sprawiają kandydatom trudność
Strefy czasowe to temat, na którym potykają się pewni siebie kandydaci, dlatego osoby prowadzące rozmowy kwalifikacyjne sprawdzają go, aby ocenić poziom ich wiedzy. Podstawowe pytanie zawsze brzmi: „jak przechowują i porównują Państwo znaczniki czasu pochodzące z różnych regionów?”
Profesjonalna odpowiedź to nie funkcja, lecz zasada: przechowywać wszystko w UTC, a konwertować wyłącznie na obrzeżach systemu, podczas wyświetlania. Gdy model przechowywania jest poprawny, większość zapytań staje się prosta.
- timestamp a timestamptz
- Konwersja między strefami
- UTC jako źródło prawdy
timestamp a timestamptz
PostgreSQL ma dwa typy znaczników czasu, a ich pomylenie jest jednym z najczęstszych błędów podczas rozmów kwalifikacyjnych.
timestamp(bez strefy czasowej): wartość czasu zegarowego z nieprzypisaną strefą. Przechowuje dokładnie to, co zostanie przekazane.timestamptz(ze strefą czasową): wewnętrznie przechowywany jako UTC; przy wprowadzaniu konwertuje wartość ze strefy sesji, a przy wyprowadzaniu konwertuje ją z powrotem.
Wbrew nazwie timestamptz nie przechowuje strefy; przechowuje dokładny moment w czasie w UTC. Ten szczegół robi dobre wrażenie podczas rozmowy kwalifikacyjnej.
CREATE TABLE events (
id bigint,
occurred_at timestamptz -- recommended: an absolute instant
);Przechowywanie w UTC i konwersja na obrzeżach systemu
Złota zasada. Należy zapisywać momenty w UTC (używając timestamptz), a na lokalną strefę konwertować je dopiero podczas prezentowania użytkownikowi. Pozwala to uniknąć niejednoznaczności związanych ze zmianą czasu i zapewnia poprawne sortowanie według czasu w każdym miejscu.
Jeśli padnie pytanie „dlaczego UTC?”, proszę odpowiedzieć: UTC nie podlega zmianom czasu letniego, więc ta sama wartość czasu zegarowego nigdy nie występuje dwukrotnie ani nie jest pomijana, w przeciwieństwie do czasu lokalnego.
-- Display a UTC instant in a user's zone (Postgres)
SELECT occurred_at AT TIME ZONE 'America/New_York' AS local_time
FROM events;Podwójne znaczenie AT TIME ZONE
AT TIME ZONE to sprytna konstrukcja i częste źródło pomyłek, ponieważ w zależności od typu danych wykonuje dwie przeciwne operacje:
- Zastosowana do
timestamptzkonwertuje absolutny moment do danej strefy i zwraca zwykłytimestamp(czas wskazywany przez zegar w tej strefie). - Zastosowana do zwykłego
timestampinterpretuje ten czas zegarowy jako czas w danej strefie i zwraca wartośćtimestamptz.
Cała sztuka polega na rozpoznaniu, w którym kierunku działa konwersja.
-- timestamptz -> local wall clock (returns timestamp)
SELECT TIMESTAMPTZ '2024-03-01 12:00:00+00'
AT TIME ZONE 'Asia/Tokyo'; -- 2024-03-01 21:00:00
-- plain timestamp interpreted in a zone (returns timestamptz)
SELECT TIMESTAMP '2024-03-01 12:00:00'
AT TIME ZONE 'Asia/Tokyo'; -- 2024-03-01 03:00:00+00Pobieranie bieżącego momentu
Warto znać funkcje zwracające „teraz”. NOW() i CURRENT_TIMESTAMP zwracają w Postgresie wartość typu timestamptz. Zwracają czas rozpoczęcia transakcji, a nie instrukcji, co ma znaczenie w przypadku długich transakcji.
Aby jawnie uzyskać UTC, należy wykonać konwersję: NOW() AT TIME ZONE 'UTC'. W MySQL funkcja UTC_TIMESTAMP() zwraca czas UTC bezpośrednio.
SELECT
NOW() AS tx_start_tz,
NOW() AT TIME ZONE 'UTC' AS utc_walltime;Czas letni jest prawdziwym wrogiem
Osoby prowadzące rozmowy kwalifikacyjne uwielbiają przypadki brzegowe związane z DST. Gdy zegary przesuwają się do przodu, lokalna godzina wskazywana przez zegar nie istnieje; gdy przesuwają się do tyłu, pewna godzina powtarza się. Przechowywanie czasu lokalnego sprawia, że takie wartości są niejednoznaczne albo nieprawidłowe.
Przechowywanie czasu UTC całkowicie omija ten problem: każdy moment jest jednoznaczny i monotoniczny. Podanie nazwy regionu, takiej jak 'America/New_York' (zamiast stałego offsetu, takiego jak -05:00), pozwala bazie danych poprawnie zastosować reguły DST dla dowolnej daty.
-- Region name applies DST automatically for the given date
SELECT TIMESTAMPTZ '2024-07-01 12:00:00+00'
AT TIME ZONE 'America/New_York' AS summer, -- EDT (-04)
TIMESTAMPTZ '2024-01-01 12:00:00+00'
AT TIME ZONE 'America/New_York' AS winter; -- EST (-05)Grupowanie według lokalnego dnia w różnych strefach
Realistyczny problem brzmi: „liczba aktywnych użytkowników dziennie w lokalnym czasie każdego użytkownika”. Jeśli bezpośrednio obetnie się znacznik czasu UTC, granice dnia będą nieprawidłowe dla użytkowników spoza strefy UTC.
Przed obcięciem czasu do dnia należy przekonwertować go do strefy użytkownika. Konwersja przesuwa czas zegarowy tak, aby granice dni odpowiadały lokalnemu czasowi.
SELECT
DATE_TRUNC('day', occurred_at AT TIME ZONE u.tz) AS local_day,
COUNT(DISTINCT e.user_id) AS dau
FROM events e
JOIN users u ON u.id = e.user_id
GROUP BY 1
ORDER BY 1;Bezpieczne porównywanie znaczników czasu
Podczas filtrowania kolumny typu timestamptz należy porównywać ją z jednoznacznym momentem, najlepiej literałem UTC albo wartością timestamptz z offsetem. Porównanie z nieokreślonym ciągiem znaków może spowodować jego interpretację w nieprzewidywalnej strefie sesji.
Dzięki temu porównanie pozostaje jednoznaczne niezależnie od tego, kto uruchamia zapytanie.
SELECT *
FROM events
WHERE occurred_at >= TIMESTAMPTZ '2024-03-01 00:00:00+00'
AND occurred_at < TIMESTAMPTZ '2024-04-01 00:00:00+00';Epocha i znaczniki czasu Unix
Wiele systemów przechowuje czas jako epokę Unixową (liczbę sekund od 1970-01-01 UTC). Osoba prowadząca rozmowę kwalifikacyjną może pokazać Państwu kolumnę typu integer i poprosić o jej odczytanie.
- Postgres:
TO_TIMESTAMP(epoch_seconds)zwraca wartość typutimestamptz. - Z powrotem do epoki:
EXTRACT(EPOCH FROM occurred_at). - MySQL:
FROM_UNIXTIME()iUNIX_TIMESTAMP().
Wartości epoki są z definicji wyrażone w UTC, co jest jednym z powodów ich popularności przy przechowywaniu danych.
SELECT
TO_TIMESTAMP(1709294400) AS as_ts, -- from epoch
EXTRACT(EPOCH FROM NOW())::bigint AS as_epoch; -- to epochUwagi o strefach czasowych w różnych dialektach
Oto krótka mapa, która pozwoli swobodnie poruszać się w dowolnym środowisku:
- Postgres:
timestamptziAT TIME ZONEzapewniają najbogatszą obsługę. - MySQL:
TIMESTAMPautomatycznie konwertuje wartości za pomocą sesyjnej strefytime_zone;CONVERT_TZ(t, from, to)wykonuje jawną konwersję.DATETIMEnie uwzględnia strefy czasowej. - SQL Server:
datetimeoffsetprzechowuje offset;AT TIME ZONE 'name'wykonuje konwersję na podstawie nazw stref systemu Windows.
-- MySQL explicit conversion
SELECT CONVERT_TZ(event_dt, 'UTC', 'Europe/Istanbul') AS local_dt
FROM events;Głębszy przykład: sesje przechodzące przez północ
Subtelne pytanie dotyczące raportowania brzmi: jak policzyć sesje przypadające na każdy lokalny dzień kalendarzowy, jeśli sesja może przechodzić przez północ? Rozwiązanie wymaga tej samej dyscypliny: należy przekonwertować czas lokalny, a następnie przypisać go do odpowiedniego przedziału.
Początek i koniec należy przechowywać jako timestamptz; na potrzeby raportu lokalny dzień należy wyznaczyć na podstawie przekonwertowanego czasu rozpoczęcia. Jeśli sesję trzeba podzielić między dwa dni, można dołączyć tabelę obejmującą wszystkie dni, czyli day spine — to świetny temat do poruszenia jako pytanie uzupełniające.
SELECT
DATE_TRUNC('day', started_at AT TIME ZONE 'Europe/Istanbul') AS local_day,
COUNT(*) AS sessions
FROM sessions
GROUP BY 1
ORDER BY 1;Szybkie sprawdzenie
Proszę potwierdzić zalecaną strategię przechowywania danych i wyjaśnić, dlaczego jest zalecana.
Podsumowanie: strefy czasowe i znaczniki czasu
Najważniejsze zasady:
- Przechowuj UTC jako
timestamptz; do nazwanej strefy konwertuj tylko na potrzeby wyświetlania. timestamptzprzechowuje moment w UTC, a nie strefę czasową, mimo swojej nazwy.AT TIME ZONEdziała w obu kierunkach, zależnie od typu danych wejściowych: konwertuje wartość timestamptz na lokalny czas zegarowy albo interpretuje zwykły timestamp jako czas w danej strefie.- Należy używać nazw regionów (
'America/New_York'), aby reguły DST były stosowane automatycznie; należy unikać stałych offsetów. - Czas należy konwertować na lokalny przed obcięciem go do dnia, a kolumny porównywać z jednoznacznymi momentami UTC.
Często zadawane pytania
Czy lekcja „Strefy czasowe i znaczniki czasu” jest bezpłatna?
Tak — pełny tekst „Strefy czasowe i znaczniki czasu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Coding Interview Prep, przejdź na CoddyKit PRO. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.
Co nauczysz się w „Strefy czasowe i znaczniki czasu”?
Przechowywanie czasu UTC, konwersja stref oraz pułapki dotyczące znaczników czasu poruszane przez rekruterów. Ćwiczysz Coding Interview Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Coding Interview Prep?
Nie wymagamy żadnego doświadczenia. Coding Interview Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Strefy czasowe i znaczniki czasu”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Coding Interview Prep?
Tak. Każda lekcja Coding Interview Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Działania na datach i interwały
- Obcinanie i grupowanie dat
- Analizowanie i formatowanie ciągów znaków
- Strefy czasowe i znaczniki czasu