Времевите клейма на Unix са цял брой секунди от 1 януари 1970 г. UTC.
Ако приемем, че имате предвид, че имате цяла колона във вашата база данни с това число, тогава часовата зона на вашия сървър на база данни е без значение.
Първо преобразувайте клеймото за време в datetime
тип:
SELECT DATEADD(second, yourTimeStamp, '1970-01-01')
Това ще бъде UTC datetime
който съответства на вашето времево клеймо.
След това трябва да знаете как да коригирате тази стойност към вашата целева часова зона. В голяма част от света една зона може да има множество отмествания поради лятното часово време.
За съжаление, SQL Server няма възможност да работи директно с работни часови зони. Така че, ако използвате например тихоокеанското време в САЩ, няма как да знаете дали трябва да извадите 7 часа или 8 часа. Други бази данни (Oracle, Postgres, MySql и т.н.) имат вградени начини да се справят с това, но уви, SQL Server не го прави. Така че, ако търсите решение с общо предназначение, ще трябва да направите едно от следните:
-
Импортирайте данни за часовата зона в таблица и поддържайте тази таблица при промяна на правилата за часовата зона. Използвайте тази таблица с куп персонализирана логика, за да разрешите отместването за определена дата.
-
Използвайте
xp_regread
за да стигнете до ключовете на системния регистър на Windows, които съдържат данни за часовата зона, и отново да използвате куп персонализирана логика, за да разрешите отместването за определена дата. Разбира се,xp_regread
е лошо нещо, изисква определени разрешения и не се поддържа или документира. -
Напишете SQLCLR функция, която използва
TimeZoneInfo
клас в .Net. За съжаление, този изисква "опасен" SQLCLR асембли и може да причини лоши неща.
IMHO, нито един от тези подходи не е много добър и няма добро решение това да се направи директно в SQL. Най-доброто решение би било да върнете UTC стойността (или оригиналното цяло число, или datetime
в UTC) към кода на вашето приложение за повикване и вместо това направете преобразуването на часовата зона там (с, например, TimeZoneInfo
в .Net или подобни механизми в други платформи).
ОБАЧЕ - извадихте късмет, че Кувейт е (и винаги е бил) в зона, която не преминава към лятно часово време. Винаги е било UTC+03:00. Така че можете просто да добавите три часа и да върнете резултата:
SELECT DATEADD(hour, 3, DATEADD(second, yourTimeStamp, '1970-01-01'))
Но имайте предвид, че това не е решение с общо предназначение, което ще работи във всяка часова зона.
Ако желаете, можете да върнете един от другите типове SQL данни, като например datetimeoffset
, но това само ще ви помогне да отразите, че стойността е компенсирана за три часа спрямо всеки, който може да я погледне. Това няма да направи процеса на преобразуване по-различен или по-добър.
Актуализиран отговор
Създадох проект за поддръжка на часови зони в SQL Server. Можете да го инсталирате от тук . След това можете просто да конвертирате така:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'Asia/Kuwait')
Можете да използвате всяка часова зона от базата данни tz на IANA , включително тези, които използват лятно часово време.
Все още можете да използвате метода, който показах по-горе, за да конвертирате от unix timestamp. Като ги съберем заедно:
SELECT Tzdb.UtcToLocal(DATEADD(second, yourTimeStamp, '1970-01-01'), 'Asia/Kuwait')
Актуализиран отново
С SQL Server 2016 вече има вградена поддръжка за часови зони с AT TIME ZONE
изявление. Това също е налично в Azure SQL база данни (v12).
SELECT DATEADD(second, yourTimeStamp, '1970-01-01') AT TIME ZONE 'Arab Standard Time'