Drupal a Datetime / Timestamp políčka - jak správně ukládat a vypisovat datumy podle nastavení timezone v PHP

Drupal 8 (a tedy i nyní Drupal 9) ukládají Datetime políčka ve formátu 2020-07-23T13:58:36, kde dojde k automatické konverzi na UTC čas. S tím pak mohou nastat jisté problémy.

Úvod

Pokud stavíte web, kde si uživatelé mohou nastavovat vlastní timezone, můžete brzy zašít řešit problémy, jak vlastně správně ukládat čas do databáze. Není to žádná věda, ale je třeba si dát na pár věcí pozor. Trik je v tom, nastavovat si UTC pro DrupalDateTime.

Než začneme

Abychom minimalizovali možnosti chyb, je nejlepší si k přidat k uživateli datetime políčko, které si budeme nastavovat hned časového pásma. K tomu je dobré mít i přístup k databázi, tak si sledovat, jak se mění hodnota v závislosti na zvoleném časovém pásmu. A úplně v ideální případě je skvělé mít přístup (například přes vzdálenou plochu) na nějaký počítač, který je opravdu v jiném časovém pásmu.

K tomu si připravit nějaké View, které bude vypisovat hodnotu tohoto datetime políčka.

Pomocí databáze a View si můžeme vše pořádně testovat, dokud si nebudeme jistí, že vše funguje, jak má. Nyní už si to můžeme zkusit zopakovat, tentokrát pomocí vlastního kódu.

Jak ukládat datetime políčko

Já jsem řešil případ, kdy uživatel uloží svůj profil, tak by se měl uložit aktuální čas. Výsledný kód je velmi jednoduchý:

use Drupal\Core\Datetime\DrupalDateTime;
$date_object = new DrupalDateTime('now', 'UTC');
$user->set(field_datum, $date_object->format('Y-m-d\TH:i:s'));

Ale otestovat to, že vše funguje správně, zabralo pořádnou dobu.

Nejlepší je najít si políčko v databázi, a podívat se tam, jestli je čas opravdu v UTC formátu. Takže aktuálně je máme např. letní středoevropský čas. Takže oproti UTC jsme napřed o dvě hodiny. To znamená, že pokud v 8:35 ukládám čas, v databázi by mělo být 6:35.

33mysql datetime

Ale pozor, to platí jen pokud daný uživatel má nastavené město / timezone v tomto časovém pásmu.

33locale settings

V okamžiku, kdy uživatel bude mít třeba nastavený Londýn, tedy jiné časové pásmo, už uložená hodnota bude 7:35.

Na to pozor, pokud jako např. administrátor, s nastaveným časovým pásmem, budete měnit nějaké datetime políčko jiného uživatele s jiným časovým pásmem, bude se to řídit podle toho administrátorského nastavení.

Jak vypsat datetime políčko

Při výpisu políčka musíme opět definovat, že používáme UTC. Pak si jej můžeme vypsat v libovolném date formátu.

use Drupal\Core\Datetime\DrupalDateTime;
$datum = '2020-07-24T06:35:23';
$date_original= new DrupalDateTime( $datum , 'UTC' );
$ts = $date_original->format('U');
$date = \Drupal::service('date.formatter')->format($ts, 'date_and_time');

Závěr

Nakonec to není žádná velká věda, ale zas tak triviální to není. To ukazují i početné diskuzní příspěvky na toto téma.

Pár užitečných odkazů:

Programmatically set a datetime field https://drupal.stackexchange.com/questions/215332/programmatically-set-…
New Datetime API https://www.drupal.org/node/1834108
The Time Zone Converter https://www.thetimezoneconverter.com/