Ukládat DateTime vždy jako GMT

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
michal.lohnisky
Člen | 64
+
+1
-

Ahoj,

používám Nette ~2.2.0. Při ukládání do sloupce typu datetime v MySQL používám klasicky \Nette\Utils\DateTime. Protože programuju aplikaci, kterou používají lidé v různých časových pásmech, chci si do DB ukládat čas v timezoně GMT (jak kdyby bez timezony). Proto bych potřeboval aby se těsně před uložením / těsně po výběru z DB konvertovala timezone na/z GMT z/na timezone uživatele (PHP). Nepřipadá mi jednoduché podědit třídy MySqlDriver a ResultSet a nacpat je zase do Nette.

Jde to nastavit nějak jednoduše na jednom nebo na dvou místech?

michal.lohnisky
Člen | 64
+
0
-

Spřízněné téma jsem našel na Hrachově blogu. Tuto funkcionalitu lze implementovat docela jednoduše. Nastavení by probíhalo v neonu:

database:
	options:
		utc: true	#defaultně false, abychom se vyhnuli BC breaku

Při ukládání do DB by se DateTime naklonoval a upravila by se timezona na UTC ->setTimezone(new \DateTimeZone('UTC')), případně na tu, kterou aktuálně DB používá. Při výběru z DB by se nastavila timezona, pomocí které jsme do DB ukládali, a upravila by se na právě používanou v PHP (->setTimezone(new \DateTimeZone(date_default_timezone_get()))).

Klidně připravím i pull request, ale nepadají mě dvě místa, kam tuto funkcionalitu umístit:

  1. Vrstva DB driverů – při ukládání a při výběru
  2. Vrstva vyšší, společná pro všechny drivery – při ukládání a při výběru

Mohl by se k tomu vyjádřit někdo povolanější (@DavidGrudl @hrach) ?

MartyIX
Člen | 217
+
0
-

A co mít prostě všechna data v DB uložená v UTC a používat komponenty, které zobrazí přepočtený čas podle uživatelovi timezony? To je určitě jednodušší (méně bugů) a přijde mi to i čistější než si svazovat mysql driver s uživatelem (Nebudou na to zapomínat ostatní vývojáři? Nepovede to k ošklivým chybám v nějakých připadech? Co třeba cron skripty, kde asi nemáš přihlášeného žádného uživatele? Nezkomplikuje ti to logování chování aplikace?).

Samozřejmě si to ale udělěj, jak ti to bude nejlépe vyhovovat. Já se obecně těmto řešením, která globálně mění chování aplikace s tím, že to ušetří práci, vyhybám. Neosvědčilo se mi to – čas jsem tím víc zabil, než že bych ho ušetřil. :-)

hrach
Člen | 1838
+
0
-

@michal.lohnisky: mozno se inspirovat u nextras/dbal, ktery to ma vyreseno. pro ukladani ma dva specialni modifikatory a umoznuje potrebne nastaveni driveru pro zpetnou kompatibility, kdyz nekdo do datetime (tj. bez podpory timezony) ukladal timezonovany udaj.

@MartyIX cela logika kolem tohoto je nesmiru slozita a napsat clanek a knihovnu neni jednoduche. Proc neukladat data v UTC? Protoze (v napr. v MySQL):

  • kvuli selectu a funkcim jako TIMEDIFF je treba mit nastavenou potrebnou timezonu
  • pokud mam ne-UTC working timezonu, mysql neumi (nema na to syntaxu) ulozit do timestampu datum v jinym timezone, nez je working.
  • typy datetime aspol. working timezonou vubec ovlivneny vubec. Coz je na jednu stranu vyhoda, jak pises, na druhou stranu db uz neumi ty vychytavky, jako TIMEDIFF, ktery v ne-utc timezonach zohlednuje ty veci, ktery chces (letni casy, historicke souvislosti, etc.).
michal.lohnisky
Člen | 64
+
0
-

@hrach mě přivedl na následující myšlenku implementace:

Jak by to mělo fungovat:

database:
	options:
		connectionTz: 'UTC' # defaultně date_default_timezone_get() nastavená při připojení k DB
		applicationTz: null	# defaultně NULL (NULL znamená aktuálně nastavená date_default_timezone_get() při provádění query)

Při vytvoření spojení se nastaví DB timezone na connectionTz. Ukládání do DB a výběr z DB pak probíhá následovně (příklad je pro MySQL):

+-------------------------------------------------------------------------+---------------------------------------------------------------------------------------+
                             ukládání do DB                               |                                          výběr z DB
+-------------------------------------------------------------------------+---------------------------------------------------------------------------------------+
    moje aplikace     |          Nette          |                      databáze                    |                     Nette                    |  moje aplikace
----------------------+-------------------------+--------------------------------------------------+----------------------------------------------+----------------
                      |                         |                                                  |                                              |                
datetime, date, time: |                         |                                                  |                                              |                
´´´´´´´´´´´´´´´´´´´´  |                         |                                                  |                                              |                
-------> jakákoliv Tz +> modify to connectionTz +----------------------> SAVE ---------------------+> set connectionTz -> modify to applicationTz +--------------->
                      |                         |                                                  |                                              |                
timestamp:            |                         |                                                  |                                              |                
´´´´´´´´´             |                         |                                                  |                                              |                
-------> jakákoliv Tz +> modify to connectionTz +> modify to UTC -> SAVE -> modify to connectionTz +> set connectionTz -> modify to applicationTz +--------------->
                      |                         |                                                  |                                              |                

Připravil jsem zatím tento commit. Pokud by se Vám to líbilo, je třeba doimplementovat tyto věci do ostatních driverů.

Toto řešení je zpětně kompatibilní, stejně jak psal @hrach ohledně nextras/dbal (tj. když někdo do datetime ukládal timezonový údaj). Dále lze při přihlášení uživatele pomocí date_default_timezone_set() nastavit jeho vlastní timezonu a dále pak už jen používat ->format('j.n.Y H:i:s') bez jakéhokoliv helperu a vše bude v čase, který uživatel očekává.

Vidí někdo nějaký problém?

Editoval michal.lohnisky (17. 4. 2015 12:36)

michal.lohnisky
Člen | 64
+
0
-

@hrach @DavidGrudl Bump.