Zegar

Standard daty i czasu ISO 8601 a PHP

Hej!

Czy znasz standard ISO 8601? Czy wiesz jak sformatować datę i czas zgodnie z standardem ISO 8601? Czy wiesz który format w PHP jest niepoprawnym formatem ISO 8601? Czy wiesz dlaczego tak jest? Jeśli te pytania Cię zaciekawiły, zapraszam do czytania.

Standard ISO 8601

Międzynarodowa norma ISO określająca sposób zapisu daty i czasu

https://pl.wikipedia.org/wiki/ISO_8601

Jest to standard zapisu daty i czasu, powszechnie używany w internecie. Kilka przykładów:

2021-05-06
2021-05-06T20:17:24+00:00
2021-05-06T20:17:24Z
20210506T201724Z
2021-W18

Dodatkowo, standard definiuje zapis interwałów czasowych, ale to nie temat tego wpisu.

Formatowanie daty ISO 8601 w PHP

Możesz to zrobić na kilka różnych sposobów:

<?php declare(strict_types=1);

echo date('c');
// 2021-05-06T20:08:33+00:00
echo (new DateTimeImmutable())->format(DateTimeInterface::ISO8601);
// 2021-05-06T20:08:33+0000
echo (new DateTimeImmutable())->format(DATE_ISO8601);
// 2021-05-06T20:08:33+0000
echo (new DateTimeImmutable())->format(DateTimeInterface::ATOM);
// 2021-05-06T20:08:33+00:00
echo (new DateTimeImmutable())->format(DATE_ATOM);
// 2021-05-06T20:08:33+00:00

Błędny format ISO 8601

Jeśli dobrze się przyjrzysz jakie wyniki dają powyższe przykład, to zauważysz w nich drobną różnicę.

Tak, formaty dat które definiują stałe DateTimeInterface::ISO8601 oraz DATE_ISO8601niepoprawne. Godziny i minuty w offsecie powinny być rozdzielone dwukropkiem.

Dokumentacja PHP o tym wspomina:

Note: This format is not compatible with ISO-8601, but is left this way for backward compatibility reasons. Use DateTime::ATOM or DATE_ATOM for compatibility with ISO-8601 instead.

https://www.php.net/manual/en/class.datetimeinterface.php#datetime.constants.types

W internecie natknąłem się na informację że ten zapis jest niby zgodny z ISO 8601, jednak jest to nieprawda.

Skąd ten błąd?!

Szukałem w internecie informacji na ten temat ale nie udało mi się ich znaleźć. Udało mi się za to znaleźć commit w kodzie źródłowym PHP który dodał owy, felerny format daty:

https://github.com/php/php-src/commit/e6c1ff254d0c1b246d83bdaffda0a9403fa5eeba

Commit jest z 20 lipca 2005. Autorem jest sam Derick Rethans, twórca XDebug. Wydaje mi się że jest to literówka albo błąd wynikający z niepoprawnego zrozumienia standardu ISO 8601. Napisałem e-mail do Dericka, ale póki co brak odpowiedzi. Gdy tylko odpowie to uzupełnię ten wpis. Dlatego warto zapisać się do newslettera 🙂

Co ciekawe, standard ISO 8601 zezwala na brak dwukropka w offset, ale tylko w formacie podstawowym, który nie zezwala na żadne separatory pomiędzy elementami składowymi. Wygląda on tak:

20210506T200833+0000

Niezbyt czytelne, prawda?

Natomiast dużo czytelniejszy jest format rozszerzony który wymaga separatorów:

2021-05-06T20:08:33+00:00

Większość ludzi zna ten format.

Czy zostanie to naprawione?

Póki co nie widziałem żadnego planu oznaczenia tego jako przestarzałe (ang. deprecated) czy usunięcia.

Poprawa tego formatu według mnie nie wchodzi w grę, bo taka zmiana zmieniłaby zachowanie całej masy oprogramowania na świecie – po aktualizacji PHP przestałyby akceptować stary format daty a do tego przestałyby zwracać stary typ daty. Co miałoby fatalne skutki.

Jednak PHP w ostatnim czasie prężnie się rozwija. Być może w kolejnej wersji major opiekunowie oznaczą jako przestarzałe a potem usuną niepoprawny format daty. A jak ktoś będzie nadal go potrzebował zawsze może zadeklarować u siebie stałą z tym formatem 🙂

I to tyle na dzisiaj, dzięki!

2 myśli w temacie “Standard daty i czasu ISO 8601 a PHP”

  1. moim zdaniem w wersji głównej jak najbardziej mogliby to zmienić, w końcu z definicji łamią one zgodność, jednak dla bezpieczeństwa lepiej odrzucić niepoprawne formaty całkowicie, łatwiej wyłapać błąd jeśli się nieuważnie aktualizuje kod

    P.S. warto zaznaczyć obecność kapczy tak, aby użytkownik wiedział, że musi coś odblokować zanim się naprodukuje i go odrzuci

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *