Як правильно поводитися з TimeZone в SQL Server?


34

Мій сервер локальної розробки знаходиться на Близькому Сході, але мій сервер виробництва знаходиться у Великобританії.

Мені потрібно показати дату користувачеві в їх часовому поясі. Наприклад, якщо користувач перебуває в Саудівській Аравії, то мені потрібно показати час відповідно до формату Саудівської Аравії.

Чи варто створити нову таблицю бази даних під назвою TimeZone і зберегти час у UTC?


Ефективно перетворює дати між UTC та місцевим (тобто PST) часом у SQL 2005 http://stackoverflow.com/questions/24797/effectively-converting-dates-bet
mehdi

Це веб-додаток, настільний додаток чи ...? Те, як це реалізується, сильно залежить від механізму доставки клієнта, оскільки те, що вам потрібно, залежить від клієнта.
Джон Сейгель

Цей веб, а також рідний мобільний. Так, цей ефект у різних клієнтів по-різному.
user960567

1
Схоже, ваше питання стосується не лише самої бази даних, але також передбачає розробку додатків. Це запитання про переповнення стека обов'язково вам прочитають: Перехід на літній час та найкращі практики часового поясу
Ган

Відповіді:


48

На жаль, для цього немає швидкого виправлення. Інтернаціоналізація програми повинна бути частиною перших обговорень дизайну, оскільки вона дійсно лежить в основі багатьох різних областей, включаючи порівняння дати та часу та форматування вихідних даних.

У будь-якому разі, щоб стати на шлях правильного виконання, важливо зберігати інформацію про часовий пояс із часом . Іншими словами, розуміючи, що дата / час 20130407 14:50є безглуздим без (a) включення зсуву часового поясу часового поясу UTC (примітка 1) , або (b) забезпечення того, що вся логіка, що вставляє ці значення, спочатку перетворюється на певний фіксований зміщення ( швидше за все 0). Без жодної з цих речей два задані значення часу є незрівнянними , а дані пошкоджені . (Останній метод , до речі, грає з вогнем (примітка 2) ; не робіть цього.)

У SQL Server 2008+ ви можете зберігати зсув із часом безпосередньо, використовуючи datetimeoffsetтип даних. (Для повноти, у 2005 році і раніше я додав би другий стовпець, щоб зберігати поточне значення зміщення UTC (у хвилинах).)

Це полегшує додаток для настільного типу, оскільки ці платформи зазвичай мають механізми автоматичного перетворення дати / часу + часовий пояс у місцевий час, а потім форматування для виведення даних, все залежно від регіональних налаштувань користувача.

Для Інтернету, який є суттєво відключеною архітектурою, навіть при встановленні резервних даних належним чином, це складніше, оскільки вам потрібна інформація про клієнта, щоб мати змогу здійснити перетворення та / або форматування. Зазвичай це робиться за допомогою налаштувань уподобань користувачів (програма перетворює / форматує речі перед виведенням) або просто показує речі з однаковим фіксованим форматом і зміщенням часового поясу для всіх (що це робить платформа Stack Exchange в даний час).

Ви можете бачити, як якщо дані бек-енду не налаштовані належним чином, дуже швидко вони стануть складними і хиткими. Я б не рекомендував спускатися жодним із цих шляхів, тому що у вас просто виникне більше проблем.

Примітка 1:

Зсув UTC за часовим поясом не фіксований: врахуйте економію літнього часу, коли зміщення UTC зони в залежності від значення плюс-мінус на годину. Крім того, дати літнього часу в зонах змінюються регулярно. Таким чином, використання datetimeoffset(або композиція local timeта UTC offset at that time) призводить до максимального відновлення інформації.

Примітка 2:

Йдеться про введення даних. Хоча не існує надійного способу перевірки вхідних значень, краще застосувати простий стандарт, який не передбачає обчислень. Якщо публічний API очікує типу даних, який включає зміщення, ця вимога буде зрозумілою для абонента.

Якщо це не було так, абонент повинен покладатися на документацію (якщо вони її читають), або обчислення зроблено неправильно, і т. Д. Існує менше режимів відмов / помилок, коли вимагається зміщення, зокрема для розподіленої системи ( або навіть просто веб / база даних на окремих серверах, як це буває тут).

Зберігання компенсації все одно вбиває двох птахів одним каменем; і навіть якщо це не потрібно в даний час , це робить можливість доступна пізніше , якщо це необхідно. Правда, це займає більше місця для зберігання даних, але я вважаю, що це варто компромісу, оскільки дані втрачаються, якщо вони ніколи не записуються.


3
Як я розумію, зміщення не є тим самим, як часовий пояс ... час, який зберігається в даті відміни, втрачає таку інформацію, як обізнаність літнього часу ... Детальніше: stackoverflow.com/tags/timezone/info
Пітер МакЕвой

1
@PeterMcEvoy DST тут не має жодної актуальності. datetimeoffsetозначає "це місцевий час користувача / комп'ютера, коли річ сталася" - нам не потрібно знати, чи діяв DST чи ні, оскільки задане зміщення UTC завжди є (вбудоване у datetimeoffsetзначення).
Дай

12

Я розробив комплексне рішення для перетворення часових поясів у SQL Server. Дивіться підтримку часової зони SQL Server на GitHub .

Він належним чином обробляє перетворення між часовими поясами, до та з UTC, включаючи літній час.

Це поняття подібне до рішення "T-SQL Toolbox", описаного у відповіді adss, але воно використовує більш поширені часові пояси IANA / Olson / TZDB замість Microsoft, і воно включає утиліти для збереження даних, що зберігаються як нові випуски TZDB виходить.

Приклад використання (для відповіді на ОП):

SELECT Tzdb.UtcToLocal(sysutcdatetime(), 'Asia/Riyadh') as CurrentTimeInSaudiArabia

Див . Readme на GitHub для отримання додаткових API та детального пояснення.

Також зауважте, що оскільки це рішення, що базується на АДС, воно не розраховане на ефективність як основну мету. Ще було б краще, якби ця функціональність була вбудована в SQL Server, аналогічно тому, як CONVERT_TZфункція існує в Oracle і MySQL.


6

SQL Server вніс зміни в 2005 році, де внутрішній часовий пояс зберігається в UTC. Це багато в чому пояснювалося геореплікацією та проекторами HA, що включали доставку журналів, а збереження часу доставки журналів у різних часових поясах унеможливлювало відновлення старого методу.

Таким чином, збереження всього всередині часу UTC дозволило SQL Server добре працювати в глобальному масштабі. Це одна з причин, чому економія денного світла - це біль, з якою потрібно боротися в Windows, оскільки інші продукти MS, такі як Outlook, також зберігають дату / час внутрішньо як UTC та створюють зміщення, яке потрібно виправити.

Я працюю в компанії, де у нас тисячі серверів (хоча не MS SQL-сервери, але всі види серверів) розповсюджуються по всьому світу, і якби ми спеціально не змушували все йти до UTC, ми б всі божевільні дуже швидко.


5

Я розробив і опублікував проект «T-SQL Toolbox» на кодоплексі, щоб допомогти всім, хто бореться з обробкою датою та часовим поясом у SQL Server. Це відкритий код і абсолютно безкоштовний у використанні.

Він пропонує простий UDF для перетворення дат, використовуючи звичайний T-SQL з додатковими таблицями конфігурації.

У вашому прикладі ви можете використовувати такий зразок:

SELECT [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] (
    'GMT Standard Time', -- the original timezone in which your datetime is stored
    'Middle East Standard Time', -- the target timezone for your user
    '2014-03-30 01:55:00' -- the original datetime you want to convert
)

Це поверне для користувача перетворене значення дати.

Список усіх підтримуваних часових поясів можна знайти в таблиці "DateTimeUtil.Timezone", яка також надається в базі даних T-SQL Toolbox.


Такий інструментарій може здатися відмінною підмогою для розробника. Однак скалярна функція - це чорне поле для оптимізатора запитів. Це означає, що коли я застосую вашу функцію до стовпця, таблиці конфігурації, які ви згадуєте, будуть потрапляти стільки разів, скільки є рядки в наборі результатів (за умови, що я використовую функцію лише у пункті SELECT). Це не здається приємною перспективою з точки зору продуктивності. Я не дуже перевіряв ваш інструментарій, тому не можу сказати точно, це лише загальна проблема, заснована на тому, що я знаю.
Андрій М

Андрій, впевнений, ти маєш рацію з точки зору виступу. Таблиці запитів UDF розроблені не для масових операцій з даними, а для простого використання. Тим не менш, вони виконують цілком нормально, аж до близько 100 000 записів на моїй машині.
adss

2
Якщо вам доведеться обробити більше записів у своєму випадку використання, а продуктивність має значення, вам слід подумати про збереження попередньо обчислених даних. Але навіть тоді ці UDF можуть допомогти зберегти значення часу даних у необхідних темзонах.
adss

З моєї точки зору, це питання стосується не продуктивності, а більше просто отримання базової функціональності. Можливість повернути точну інформацію з запиту - це перше. Опрацювання якоїсь темп-таблиці для кешування речей, а потім посилання на це в запиті, або якщо ви обробляєте його для підвищення продуктивності, стає другорядним.
Дія

1

Можливо, я пропускаю щось очевидне, але якщо все, що ви хочете зробити, це відображення дати за допомогою часового поясу та мовного формату користувача, найпростіший спосіб - завжди зберігати дати в UTC у базі даних та дозволяти клієнтській програмі конвертувати з UTC у локальну часовий пояс і використовуйте регіональні налаштування користувача, щоб відповідно відформатувати дату.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.