Jak poprawanie zarządzać czasem w aplikacjach?

author-avatar
Kamil Foltyniak
5 min czytania02.06.2024
post-image

Zarządzanie datami w aplikacjach często może być źródłem kłopotów. Problemy pojawiają się w sytuacjach, gdy nasza aplikacja może być dostępna dla osób w różnych miejscach na świecie, a daty są zapisywane w niepoprawnym formacie. W tym artykule dowiemy się, dlaczego daty w systemie należy przechowywać w standardzie UTC i czym są strefy czasowe.

Na czym polega problem?

Wyobraźmy sobie, że w naszej aplikacji użytkownik może dodawać komentarze. Po dodaniu komentarza data jego utworzenia jest zapisywana do bazy danych zgodnie z datą systemową serwera, na którym stoi nasza aplikacja. Załóżmy, że taki serwer jest w Polsce, więc zapisuje do bazy danych jako datę dodania komentarza bieżącą datę w Polsce, czyli np. 01-01-2024 12:00.

Jeżeli komentarz dodał użytkownik z Polski, to w aplikacji wyświetli mu się data dodania 01-01-2024 12:00. Do tego momentu jest OK. Ale co się stanie, gdy komentarz dodał użytkownik z Portugalii?

Z racji tego, że aplikacja jako moment dodania komentarza bierze czas serwerowy, to do bazy danych zostanie wstawiona również data 01-01-2024 12:00.  Użytkownik z Portugalii zobaczy w przeglądarce również taką samą datę. Niestety, taka informacja może wywołać u niego zmieszanie, ponieważ w momencie dodawania komentarza w Polsce jest co prawda godzina 12:00, to jednak ze względu na inną strefę czasową w Portugalii będzie godzina 11:00.

I to właśnie godzinę 11:00, zamiast 12:00 powinien zobaczyć pod swoim komentarzem mieszkaniec Lizbony.

Nim jednak przejdziemy do rozwiązania tego problemu, najpierw musimy zrozumieć, czym są strefy czasowe i skąd wynikają różnice w czasie między krajami.

Podział na strefy czasowe

W XIX wieku, gdy ludzie zaczęli więcej przemieszczać się po świecie, zaczęto poszukiwać rozwiązania, które ułatwiłoby podróżowanie między krajami i mogłoby pomóc w ujednoliceniu czasu na całym globie. Wprowadzony został pomysł podziału świata na 24 strefy czasowe, w którym każda kolejna strefa ma inny czas, w zależności od swojego położenia względem strefy na południku zerowym. Południk zerowy przebiega przez obserwatorium Greenwich w Londynie, a czas, który panuje w tej strefie, jest czasem uniwersalnym (Greenwich Mean Time, w skrócie GMT). Ta strefa jest oznaczana jako GMT+0 i oznacza to, że od niej jest liczony czas w pozostałym strefach czasowych: im dalej na wschód, tym więcej godzin odejmujemy, a im dalej na zachód to więcej godzin dodajemy do czasu uniwersalnego. W zależności ile wynosi różnica godzin względem czasu uniwersalnego, to strefy czasowe oznacza się na przykład jako GMT+3 czy GMT-9.

Dla przykładu: jeżeli w Greenwich jest godzina 12:00, to czasem uniwersalnym jest również 12:00. Warszawa znajduje się w strefie GMT+1, co oznacza, że doliczamy jedną godzinę względem czasu uniwersalnego i na warszawskich zegarach zobaczymy godzinę 13:00. Analogicznie, jeżeli Nowy Jork jest w strefie GMT-4, to czas lokalny tam będzie wskazywał na godzinę 8:00.

tz-photo.jpg
Podział świata na 24 strefy czasowe.

Czas letni

Podział na strefy czasowe może nieco komplikować czas letni (Daylight Saving Time, DST), który obowiązuje na całym świecie (głównie w większości krajów europejskim i Ameryce Północnej). Polega on na przesunięciu wskazówek zegara w ostatnią niedzielę marca o 01:00 czasu uniwersalnego o jedną godzinę do przodu (w Polsce jest to wg czasu lokalnego z 2:00 na 3:00) oraz o cofnięciu o godzinę w ostatnią niedzielę października. Główna motywacja dla tego rozwiązania to większa oszczędność energii poprzez lepsze zarządzanie światłem słonecznym. Jeżeli przestawiamy godzinę do przodu, to zyskujemy więcej światła po południu i wieczorem, gdy wracam z pracy i chcemy zająć się obowiązkami domowymi. Dzięki temu — przynajmniej w teorii — możemy oszczędzić energię, ponieważ nie musimy używać tyle oświetlenia elektrycznego. Obecnie, to rozwiązanie jest coraz częściej krytykowane ze względu na problemy, jakie powoduje m.in. w transporcie i logistyce oraz marginalny wpływ na oszczędność energii.

Jeżeli przechodzimy na czas letni, to wtedy różnica między czasem lokalnym w Polsce a czasem uniwersalnym wynosi 2 godziny, co możemy oznaczyć jako GMT+2.

Różnica między GMT i UTC

W kontekście pracy z datami często obok skrótu GMT używany jest również skrót UTC (Coordinated Universal Time).  Najczęściej są one traktowane jako synonimy i można je stosować wymiennie, ale warto wprowadzić tutaj rozróżnienie.

GMT jest oznaczeniem wskazującym na czas słoneczny w Greenwich, a zapis GMT+0 oznaczeniem tej strefy czasowej. Pozostałe strefy czasowe przyjmują oznaczenia zgodne z różnicą od czasu GMT — czyli np. GMT-5 dla Nowego Jorku albo GMT+2 dla czasu letniego środkowoeuropejskiego.

UTC jest następcą standardu GMT stosowanym na całym świecie, który uwzględnia jego liczenie za pomocą zegarów atomowych, które są dokładniejsze. W praktyce wskazuje on na ten sam czas co GMT, czyli czas UTC+02:00 oznacza czas w strefie czasowej GMT+2.

GMT jest zarówno strefą czasową jak i standardem czasu, natomiast UTC jest tylko standardem czasu.

Jak poprawnie zapisywać daty?

Do zapisu dat używamy międzynarodowego standardu ISO-8601. W zależności od tego, dla jakiej strefy czasowej chcemy zapisać datę, możemy użyć dwóch formatów:

  • dla czasu uniwersalnego:
    YYYY-MM-DDThh:mm:ssZ
  • dla innych stref czasowych:
    YYYY-MM-DDThh:mm:ss+hh:mm

W obu przypadkach T oddziela datę od godziny, a dla czasu uniwersalnego Z wskazuje na czas Greenwich (Zulu time).

Najlepiej pokazać to na przykładzie. W momencie pisania tego artykułu mamy w Polsce 17 marca 2024, godz. 12:00. Polska jest w strefie czasowej GMT+1, co oznacza, że jest 1 godzinę za czasem uniwersalnym. Zgodnie ze standardem ISO możemy taką datę zapisać na dwa wymienione wyżej sposoby:

  • dla czasu uniwersalnego:
    2024-03-17T11:00Z
  • dla naszej strefy czasowej:
    2024-03-17T12:00+01:00

Zauważ, że dla czasu uniwersalnego podajemy czas o godzinę wstecz. Każdy z tych formatów jest właściwy, jednak w aplikacjach powinniśmy się skłaniać do używania formatu YYYY-MM-DDThh:mm:ssZ. Jest on łatwiejszy w zrozumieniu, czytelniejszy i bardziej uniwersalny. Niezależnie od tego, w jakiej strefie czasowej jesteśmy i czy mamy czas letni, data zawsze wygląda tak samo i pokazuje czas w Greenwich.

W Javascripcie możemy otrzymać datę w formacie ISO używając metody toISOString z klasy Date.

new Date().toISOString();
// 2024-03-17T11:00:00.000Z

Podsumowanie

Wracając do problemu omawianego na początku artykułu, jeżeli zapiszemy datę dodania komentarza w czasie uniwersalnym, to z łatwością będziemy mogli przekonwertować taką datę na czas lokalny, który jest na urządzeniu użytkownika. Niezależnie od tego, w którym miejscu na świecie użytkownik dodał komentarz, to data wyświetli się odpowiednio dla innych użytkowników korzystających z naszej aplikacji w innych częściach globu, zgodnie z ich czasem lokalnym.

Jeżeli użytkownik z Pekinu (GMT+8) doda komentarz o godz. 20:00 czasu lokalnego w Pekinie, to zapiszemy tę godzinę jako 12:00 czasu uniwersalnego (2024-03-17T12:00:00.000Z).  Użytkownik z Warszawy (GMT+1) zobaczy z kolei, że komentarz chińskiego użytkownika  został dodany o 13:00 czasu polskiego.

Zawsze należy przechowywać daty w formacie ISO ze wskazaniem na strefę czasową, nawet jeżeli zakładamy, że aplikacja będzie odwiedzana tylko przez użytkowników z Polski. Uchroni nas to przed potencjalnymi błędami związanymi z wyświetlaniem daty, które niejednokrotnie mogą być poważnymi problemami, które będą uniemożliwiały użytkownikowi interakcje z systemem.