Kieg: semmi bajunk sem lesz, ha (mármint unixról beszélve, és feltéve, hogy nem AIX5-ös kőkorszaki rendszerekről van szó) a TZ-t meg ORA_SDTZ-t is beállítjuk Europe/Budapest-re, de ennek nincs köze a systimestamp-hoz; a LOCALTIMESTAMP-ot meg a CURRENT_TIMESTAMP-ot lehet velük állítani.
A pillanatnyi állást a következőképpen foglalnám össze:
1. a SYSTIMESTAMP a szerver localtime-ja
2. TZ, ORA_SDTZ, SESSIONTIMEZONE nem befolyásolja
3. (Az én esetemben legalábbis) nincs TZD része, TZR=+02:00
4. Még nem tudom, hogy ha a DBTIMEZONE Europe/Budapest lenne, akkor volna-e nekije.
5. Át lehet alakítani UTC-re (és bármi másra is persze)
6. Az UTC-vel lehet jól matekozni.
7. A megmatekozott UTC-t szeretném arra a localtime-re konvertálni, ami a szerver helyi ideje. Na ehhez is nagyon jó lenne, ha a DBTIMEZONE rendesen lenne töltve.
Igy a héven ülve a következö két kérdés gyötör:
1. ha ALTER DATABASE SET TIMEZONE = 'Europe/Budapest' paranccsal (utána stop+start) meghaxoljuk az adatbázist, az változtat-e a DBTIMEZONE értékén?
2. változtat-e a syslocaltime TZD részén?
3. ha nem, akkor van-e valami, ami változtat?
a systimestamp szerintem egyszerűen a unix systime-ja és tz-je. maga a vekker. ebből ki lehet számolni az aktuális utc-t, abból meg bármit. és a unixod ha megkérdezik mi az időzóna, akkor azt mondja hogy 2, télen meg hogy 1. nem pedig azt hogy europe/budapest.
és ez így kevés. ugyanis az hogy 2015 04 30 15:41 +02:00 az lehet europe/budapest és lehet africa/johannesburg is. és nem mindegy melyik, ugyanis délafrikában nincs téli-nyári váltás.
V1: SELECT systimestamp + NUMTODSINTERVAL(-60,'DAY') from dual;
Sajnos ez rossz válasz, mert nem veszi figyelmebe, hogy akkor még téli idő (CEST) volt itt. (Az (5302)-es 'kimenet' részében a középső sor.)
nem nem veszi figyelembe, hanem nem tudja hogy mi a helyi időzóna. nekem ugy tűnik hogy az időzónád egy fix offsettel van definiálva. a +2:00 nevű időzónában nincs téli-nyári időszámítás.
V2: SELECT ((systimestamp at time zone '+00:00') + NUMTODSINTERVAL(-60,'DAY')) at time zone 'Europe/Budapest' from dual;
Na ez már jobb (az (5302)-es 'kimenet' részében az utolsó sor.), csak még a belehardkódolt 'Europe/Budapest' helyett kellene valami flexibilis adat.
ez azt csinálja, hogy a mostani időt veszi utc-ben, levesz belőle 60 napot, és átszámolja az eredményt magyar időre.
az at time zone '+00:00' ki is hagyható, ugyanazt adja. az adattípus amit használsz az egy olyan valami, ami tárolja az időt mint értéket, és az időzónát is, amiben értelmezni kell. a systimestamp at utc es a systimestamp at budapest értékek ekvivalensek, ugyanazt a pillanatot jelentik az időegyenesen a világ történelmében. attól hogy konvertálgatsz a zónák között nem változik az érték, csak a "mértékegység". átváltod literre, hozzáadsz kétdecit, kiírod pintben. ha nem váltottad volna literre, ugyanaz lenne az eredmény.
Például van olyan, hogy
ALTER SESSION SET TIME_ZONE = 'Europe/Budapest'; ennek fordítottja:
SELECT sessiontimezone FROM dual;
válasz: Europe/Budapest
Tök jó. De amikor 'csak úgy' elindítom az SqlPlus-t, akkor a SESSIONTIMEZONE is, meg DBTIMEZONE is csak '+02:00', amit én információvesztésnek érzek.
Így van. Az europe/budapest az egy kulturalis-politikai fogalmat jelent. Hogy pontosan mit, azt a jogszabályok és bizonyos nemzetközi egyezmények tartalmazzák. A TZDATA nevű kvázistandard formátumban letölthető, az ICANN maintaineli. Ebből generálja mindenki a saját naptár szoftverét. (a linux kernel, az ora adatbázis, a java, az mfc és így tovább) Rendszeresen változik, mint amit írtam Szevasztopolról.
Vannak ennél bénább időzóna megadások, pl a +02:00. Ennek az értelmezéséhez nem kell tudni a világ összes országából hogy mit döntött a parlament mikor lesz az óraátállítás, egyszerű matematikai művelettel elvégezhető a "konverzió", műszaki felhasználásra úgy ahogy alkalmas, de inkább buta mint a főd.
Az alter sessionn-el beállíthatod magadnak amit akarsz. A default a kliens oprendszeréből jön. Ha van ORA_STDTZ akkor onnan, ha nincs akkor pl az unixtól kérdezi meg. Esélyes hogy a megfelelő unix rendszerhívás is aktuális offsetet ad vissza, nem pedig rendes időzóna nevet.
A dbtimezone annyiban más, hogy installkor kell megadni, és az lesz. Ha egy fix offsetet adtak meg akkor az, ha rendes regionevet, akkor az.
én úgy látom, azt kellene kitaláld, hogy honnan tudod meg mi most a helyi időzóna.
Szóval azért valahol benne van a kis agyában a '+02:00' ilyenkor is... elannyira, hogy ha viszont TZ-t is, meg az ORA_SDTZ-t is beállítom Europe/Kiev-re, akkor meg ezt látom:
Szóval a localtimestamp.ot lehet TZ/ORA_SDTZ útján hangolni, a systimestamp viszont valahonnan máshonnan jön, még csak nem is a DBTIMEZONE-ból... esetleg az Oracle szervert futtató gépből?
Mondjuk van egy olyan NLS_ environment változó, hogy ORA_SDTZ, ha az be van állítva hívás előtt, akkor abból lesz a SESSIONTIMEZONE. Ez is valami, többé-kevésbé.
Később: ha TZ=Europe/Kiev, akkor SESSIONTIMEZONE='+03:00', de ha ORA_SDTZ=Europe/Kiev, akkor SESSIONTIMEZONE='Europe/Kiev'
A DBTIMEZONE pedig instance-onként különbözik, +00:00, +01:00 és +02:00 fordul elő. Ettől függetlenül a SESSIONTIMEZONE mindenütt '+02:00' (hacsak nem variálok a környezeti változókkal a fentiek szerint)
az a kérdés, hogy mi a systimestamp-od időzónája. asszem mindig dbtimezone.
select to_char(systimestamp, 'tzr') from dual;
namost timezone-t megadni legalabb haromféleképpen lehet. offsettel (+2:00), rövidnévvel amivel csak a szopás van és nem javasolt (CET) és tzregionnal (europe/budapest). nekem erőst úgy tűnik, hogy nálad offsettel van megadva, nem szaroztak. ezért abban soha nem lesz téli-nyári váltás, mindig +2 és kész.
én azt mondom, hogy meg kell próbálni minnél függetlenebbül működni a környezettől.
- a select systimestamp at time zone 'UTC' from dual; az midnenképp megmondja az aktuális dátumot utc-ben. ha mégsem, az egyértelműen az üzemeltetés problémája, nem a fejlesztőé
- select to_char(from_tz(cast (to_date ('2012 02 02 13:45','yyyy mm dd hh24:mi') as timestamp), 'europe/budapest'),'TZD') from dual; ez mindenképpen megmondja egy magyar idő szerinti dátumról hogy tél vagy nyár.
sajnos arra, hogy egy adott zónában melyik a téli és melyik a nyári név, nem tudok tuti megoldást. elég csúnya, de le lehet hardkódolni hogy megkérdezzük a jan-1-et, és amit arra ad, az a télinek a neve.
(De ha valaki tudja, hogyan lehet az Orából visszanyerni, hogy az instance beállítása 'Europe/Budapest' vagy 'Canade/Central' vagy mi, akkor szóljon, legyen szíves!)
DECLARE ts_server_lt TIMESTAMP WITH TIME ZONE; ts_server_utc TIMESTAMP WITH TIME ZONE; ts_past_lt TIMESTAMP WITH TIME ZONE; ts_past_utc TIMESTAMP WITH TIME ZONE; BEGIN ts_server_lt := SYSTIMESTAMP; /* ts_server_utc := SYS_EXTRACT_UTC (SYSTIMESTAMP); */ ts_server_utc := ts_server_lt AT TIME ZONE '+00:00';
dbms_output.put_line ('past lt=' || ts_past_utc at time zone 'Europe/Budapest'); END; /
Kimenete:
lt= 20150430.114223.613754 +02:00 utc=20150430.094223.613754 +00:00 past lt= 20150301.114223.613754 +02:00 past utc=20150301.094223.613754 +00:00 past lt=20150301.104223.613754000 +01:00
A legutolsó sor lenne a helyes megfejtés, de csak akkor, ha nem lenne belehardkódolva az 'Europe/Budapest'... Nyomozok tovább.
minden valamilyen session-ben történik. minden sessionnek van egy nls settingje, meg pl timezoneja meg egy csomó egyebe.
sokféle módon jönnek létre sessionök, és mindegyiknél máshonnan jönnek a defaultok erre. vagy a defaultot kell beállítani, vagy egyszerűen a megfelelő alter sessionökkel elrendezni a dolgot explicit.
iszonyat mennyi időt töltöttem már időzónák meg hasonlók megértésével és kódolásával. mindenféle rendelkezésreállási meg sla riportokon. örülök ha másnak is segít.
az hogy az offset 2 óra nem jó szinte semmire, mert lehet hogy europe/budapest vagy nyáron, de az is lehet hogy europe/bucharest vagy télen. ha meg neked kell tudni hogy most nyár van vagy tél, akkor ott vagy ahonnan indultál.
én nagyon nemzetközi témában dolgozom, itt elképzelhetetlen hogy egy adatbázis ne UTC dbtimezone-al menjen. nincs tapasztalatom hogy milyen az ha a dbtimezone egy local time, és van benne pl átállás. hogy néz ki egy audit log akkor?
azt gondolom tudod, hogy a to_char-nak explicit megmondhatod az nls date language-ot. a to_char(sysdate,'DAY','nls_date_language=hungarian') mindig azt adja hogy SZERDA (vagy ami van :-) )
Épp ez az: egy szubrutint csinálok Pro*C-ben (aztán OCI-ben is meg kell), aminek territory és language függetlenül kellene működnie. Az lenne a cél, hogy egy fv lekérdezze a kliens localtime-ot, kliens UTC-t, szerver localtime-ot, szerver UTC-t, meg még ami ezek környékén van, pl day-of-week, dst-in-effect etc.
Sőt ugyanez a fv visszaadhatná a kliens-szerver időeltérést (persze az UTC nézve), hogy a hívó program esetleg azt modhassa: 'oké, az eltérés nagyobb mint öt perc, most leállok, majd akkor futok, ha valaki beállított valamit'
Vagy csinálsz egy decode-ot ami a hétfőből egyet, a keddből kettőt csinál, és így tovább. Szerintem robosztusabb. És minden ilyen kódban explicit írni az nls-t, mert egyszer majd valaki egy japán sessionben futtatja, és fene tudja mi fog történni.
Random ötletem: a DBTIMEZONE megegyezik a to_date(SYSTIMESAMP,'TZH:TZM')-vel, akkor nincs DST, egyébként van. Rendkívül tudományos...
Off: Már az sem triviális, hogy a hét napját megkapjam, ugyanis a to_date('D') esetén territory-függő, hogy mit jelentenek az 1-7 számok. A megfejtés az, hogy lekérdezzük egy rögzített hétfői dátumra ugyanezt, és abból kalkulálunk.
sajnos ki lehet. létezik időzóna nélküli timestamp. annak is van zónája, csak az adatbázis nem tud róla hogy mi az, nekünk kell megmondani.
pl ez a két utc time ugyarra a local time-ra konvertálódik. a tzd format maskkal lehet megtudni hogy az első vagy a másiodik 2:30 aznap.
select from_tz(to_timestamp ('2015 10 25 1:30','yyyy mm dd hh24:mi'), 'UTC') at time zone 'europe/budapest' from dual; select from_tz(to_timestamp ('2015 10 25 0:30','yyyy mm dd hh24:mi'), 'UTC') at time zone 'europe/budapest' from dual;
select from_tz(to_timestamp ('2015 10 25 0:30','yyyy mm dd hh24:mi'), 'UTC') at time zone 'CET' from dual;
25-OCT-15 02.30.00.000000000 AM CET
select from_tz(to_timestamp ('2015 10 25 0:30','yyyy mm dd hh24:mi'), 'UTC') at time zone 'CEST' from dual;