sql >> Databáze >  >> RDS >> Sqlserver

Převod data a času z časového pásma na časové pásmo na serveru SQL

Unixová časová razítka jsou celé číslo sekund od 1. ledna 1970 UTC.

Za předpokladu, že máte na mysli, že máte v databázi celočíselný sloupec s tímto číslem, pak je časové pásmo vašeho databázového serveru irelevantní.

Nejprve převeďte časové razítko na datetime typ:

SELECT DATEADD(second, yourTimeStamp, '1970-01-01')

Toto bude UTC datetime která odpovídá vašemu časovému razítku.

Pak musíte vědět, jak tuto hodnotu upravit podle cílového časového pásma. Ve velké části světa může mít jedna zóna několik posunů kvůli letnímu času.

Bohužel SQL Server nemá možnost přímo pracovat s pracovními časovými pásmy. Pokud byste tedy například používali americký tichomořský čas, neměli byste žádný způsob, jak zjistit, zda máte odečíst 7 hodin nebo 8 hodin. Jiné databáze (Oracle, Postgres, MySql atd.) mají vestavěné způsoby, jak to zvládnout, ale bohužel, SQL Server ne. Pokud tedy hledáte univerzální řešení, budete muset provést jednu z následujících akcí:

  • Importujte data časového pásma do tabulky a udržujte tuto tabulku při změně pravidel časového pásma. Použijte tuto tabulku se spoustou vlastní logiky k vyřešení posunu pro konkrétní datum.

  • Použijte xp_regread získat klíče registru Windows, které obsahují data časového pásma, a znovu použít spoustu vlastní logiky k vyřešení posunu pro konkrétní datum. Samozřejmě xp_regread je špatná věc, vyžaduje udělená určitá oprávnění a není podporován ani dokumentován.

  • Napište funkci SQLCLR, která používá TimeZoneInfo třídy v .Net. Bohužel toto vyžaduje „nebezpečné“ sestavení SQLCLR a může způsobit špatné věci.

IMHO žádný z těchto přístupů není příliš dobrý a neexistuje žádné dobré řešení, jak to udělat přímo v SQL. Nejlepším řešením by bylo vrátit hodnotu UTC (buď původní celé číslo, nebo datetime v UTC) na kód vaší volající aplikace a místo toho proveďte převod časového pásma (například pomocí TimeZoneInfo v .Net nebo podobných mechanismech na jiných platformách).

OVŠEM - máte štěstí v tom, že Kuvajt je (a vždy byl) v zóně, která se na letní čas nemění. Vždy to bylo UTC+03:00. Můžete tedy jednoduše přidat tři hodiny a vrátit výsledek:

SELECT DATEADD(hour, 3, DATEADD(second, yourTimeStamp, '1970-01-01'))

Uvědomte si však, že toto není univerzální řešení, které bude fungovat v jakémkoli časovém pásmu.

Pokud byste chtěli, můžete vrátit jeden z dalších datových typů SQL, například datetimeoffset , ale to vám jen pomůže zohlednit, že hodnota je tři hodiny kompenzována pro kohokoli, kdo by se na ni mohl podívat. Proces převodu to nezmění ani nezlepší.

Aktualizovaná odpověď

Vytvořil jsem projekt pro podporu časových pásem v SQL Server. Můžete si jej nainstalovat zde . Pak můžete jednoduše převést takto:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'Asia/Kuwait')

Můžete použít jakékoli časové pásmo z databáze IANA tz , včetně těch, které používají letní čas.

Stále můžete použít metodu, kterou jsem ukázal výše, pro převod z unixového časového razítka. Dát je oba dohromady:

SELECT Tzdb.UtcToLocal(DATEADD(second, yourTimeStamp, '1970-01-01'), 'Asia/Kuwait')

Opět aktualizováno

S SQL Server 2016 je nyní integrována podpora časových pásem s AT TIME ZONE tvrzení. To je také k dispozici v Azure SQL Database (v12).

SELECT DATEADD(second, yourTimeStamp, '1970-01-01') AT TIME ZONE 'Arab Standard Time'

Další příklady v tomto oznámení.




  1. CHYBA! Soubor PID správce MySQL nebo serveru nebyl nalezen! QNAP

  2. Jak přidat omezení primárního klíče do sloupců identity do všech tabulek v databázi SQL Server - SQL Server / Výukový program TSQL, část 63

  3. Kontrola, zda dané datum zapadá do rozsahu dat

  4. 2 způsoby, jak získat minuty z hodnoty data a času v databázi Oracle