Databáze poskytuje mnoho funkcí pro práci s časem, v této kapitole se však budeme zabývat jen tím, jak čas a datum získat. Protože problémy způsobují časové zóny, rovněž se zmíním i o této problematice.
V Oracle databázi máme dva časové zdroje: systémový čas a databázový čas.
Sytémový čas
Máme dotaz:
select sysdate, systimestamp, SYS_EXTRACT_UTC(SYSTIMESTAMP) utc from dual;
Výše uvedený dotaz vrací čas operačního systému:
SYSDATE SYSTIMESTAMP UTC
------------------- ----------------------------------- ----------------------------
03.03.15 13:26:41 03.03.15 13:26:41,365645000 +01:00 03.03.15 12:26:41,365645000
Rozdíl mezi sysdate a systimestamp není jen v přesnosti. Důležité je, že sysdate neobsahuje informaci o časové zóně. V okamžiku volání sysdate se aktuální zóna "aplikuje" do hodnoty a ta se pak vrátí v dotazu. Takto zýskaný a ukládány čas může způsobit obrovské problémy:
Příklad
Představte si, že Vaše aplikace vkládá do sloupečku hodnotu SYSDATE pro zaznamání vzniku řádku a db server běží v Praze. Pokud db server přesune do Austrálie - nově vzniklé hodnoty budou ukládány s aplikovaným časovým posunem +11 ale staré hodnoty byly uloženy např. s posunem +2. Pokud tedy vznikly dva řádky v rozmezí 1 minuty ale v jiných zónách (+11 a +2), výpočty nad těmito časy (např. doba mezi vložením dvou záznamů) nebudou odpovídat realitě.
Jak tedy správně ukládat čas (a datum) v databázi? Existují 2 způsoby:
- Záznam bude uložen včetně časové zóny a pro zjištění se užije SYSTIMESTAMP
- Záznam bude uložen v UTC (bez časového posunu, +0h).
Pro práci s časem se může hodit časová zóna operačního systému:
select to_char(SYSTIMESTAMP,'TZR') timezone from dual;
Výslekek je pak například
TIMEZONE
--------------------------------
+01:00
Databázový čas
S databázovým časem se pracuje podobně jako se systémovým časem. Hlavní rozdíl je v možnosti nastavení časových zón platných v rámci databáze (tedy ne pro celý operační systém) nebo pro jedno sezení (session).
Analogický dotaz k systémovému času
select CURRENT_DATE,CURRENT_TIMESTAMP,SYS_EXTRACT_UTC(CURRENT_TIMESTAMP) utc from dual;
Výsledek je pro tentokrát zcela totožný se systémovým časem:
CURRENT_DATE CURRENT_TIMESTAMP UTC
------------------- ----------------------------------- ----------------------------
03.03.15 14:10:41 03.03.15 14:10:41,411721000 +01:00 03.03.15 13:10:41,411721000
Stejne tak zjištění časové zony databáze (aktuálního sezení)
select SESSIONTIMEZONE timezone from dual;
Oproti systémovému času si můžeme nyní časovou zónu upravit podle potřeby:
ALTER SESSION SET TIME_ZONE = '+11:0';
Nastavíme si časový posun +11 hod a okamžitě zkusíme opět dotaz k získání času databáze. Můžeme porovnat výsledky:
CURRENT_DATE CURRENT_TIMESTAMP UTC
------------------- ----------------------------------- ----------------------------
04.03.15 00:15:23 04.03.15 00:15:23,064275000 +11:00 03.03.15 13:15:23,064275000
Zatímco UTC čas se nezměnil, hodnota CURRENT_DATE a CURRENT_TIMESTAMP se změnila. U hodnoty CURRENT_TIMESTAMP nám to ovšem nevadí, časová zóna je je součástí hodnoty. Zato však CURRENT_DATE nám bude vracet jiné hodnoty, které (vysvětleno výše na příkladu) nesmí být smýchány s hodnotami před změnou časové zóny.
Závěr
V databázi existuje pochopitelně nepřeberné množství funkcí pro práci s časem. Účelem tohoto článku bylo jen naťuknout tuto problematiku a poukázat na nejpalčivější problém týkající se časových zón. Nyní je již vše na samotném čtenáři, jak se tohoto tématu chopí:)Času zdar.