MySQL ignoruje letní a zimní čas

Databáze

Přechod mezi letním a zimním časem v dnešní době dělá více problémů než užitku. Jeden takový problém nastal v tréninkovém deníku, který jsem psal pro interní systém Ski Bílá.

MySQL ignoruje letní a zimní čas

Tréninkový deník je velmi jednoduchý. Každý den po celý rok závodníci zapisují, co udělali do předpřipravené tabulky. Celý tréninkový rok je rozdělen do 13 cyklů po 28 dnech. 

Přičtením dnů se posunete o hodinu mimo, někdy

V databázi mám tedy uloženo, kdy začíná tréninkový rok, což vychází okolo začátku května. Poté pomocí DATE_ADD přičítám 28 dní, a získám začátky všech cyklů v UNIX_TIMESTAMP. A zde nastal problém, že při přesunu na zimní čas jsem byl o hodinu mimo.

SELECT nazev, zacatek, UNIX_TIMESTAMP(DATE_ADD(zacatek, INTERVAL 363 DAY)) AS konec,
        UNIX_TIMESTAMP(zacatek) AS cyklus1,
        UNIX_TIMESTAMP(DATE_ADD(zacatek, INTERVAL 28 DAY)) AS cyklus2,
        UNIX_TIMESTAMP(DATE_ADD(zacatek, INTERVAL 56 DAY)) AS cyklus3,
        UNIX_TIMESTAMP(DATE_ADD(zacatek, INTERVAL 84 DAY)) AS cyklus4,
        ...
        UNIX_TIMESTAMP(DATE_ADD(zacatek, INTERVAL 336 DAY)) AS cyklus13
    FROM sezony
WHERE nazev = "2015/2016"

Během 7. cyklu se posunul čas a v tabulce se pak 1 den zopakoval a další cykly byly o den posunuty až do změny zpět na letní čas. Při přesunu zase 1 den v tabulce chyběl.

Bez UNIX_TIMESTAMP

Pokud stejný příkaz provedete, ale bez získání UNIX_TIMESTAMP, vše bude v pořádku. Dny budou sedět.

Přesun času a rozdíl mezi MySQL a PHP

Čas se ve střední Evropě posouvá ze 3:00 na 4:00 nebo ze 3:00 na 2:00. Ve Finsku, kde je o hodinu více se čas se přesouvá ze 4:00 na 5:00 nebo ze 4:00 na 3:00. V roce 2015 se čas přesouval právě 25.10. a pokud uděláme následující výpočty, budou se lišit.

SELECT time_to_sec(timediff('2010-10-25 06:00:00', '2010-10-25 00:00:00' )) / 3600

MySQL vypíše, že rozdíl je 6h, ve skutečnosti je to ale 7h jak vypíše PHP.

var_dump((mktime(6,0,0,10,25,2015) - mktime(0,0,0,10,25,2015))/3600)

Řešení

Jak vyřešit tento problém? 

První řešení by vyžadovalo také změnu kódu v PHP, protože bych musel získávat datum ze stringu. Protože ale řeším pouze celé dny, nikoli hodiny, můžu změnit datový typ z DATE na DATETIME a začátek roku nastavil na poledne. 

V případě posunu na zimní čas se UNIX_TIMESTAMP sice vrátí o hodinu zpět, což ale bude z 12:00 na 11:00, takže jsem stále ve stejném dni.

P.S. Kdyby tréninkový rok začínal v zimním čase, problému si nevšimnu. Timestamp by se posunul o hodinu dopředu, a byl bych stále ve stejném dni.


Měli jste podobný problém, nebo máte jiné řešení? Podělte se s námi v komentářích

K tomuto článku již není možné přidávat další komentáře