Тази статия разглежда основните разлики между datetime2 и datetimeoffset типове данни в SQL Server.
И двата типа данни се използват за съхранение на стойности за дата и час. И двете са много сходни, но с една ключова разлика; отместването на датата и времето съхранява изместването на часовата зона.
Това също води до отместване на датата и времето използва повече място за съхранение от datetime2 , така че ще използвате само datetimeoffset ако имате нужда от изместване на часовата зона.
Ето таблица, която очертава основните разлики между тези два типа.
Функция | datetimeoffset | datetime2 |
---|---|---|
Съвместим с SQL (ANSI и ISO 8601) | Да | Да |
Период от време | 0001-01-01 до 9999-12-31 | 0001-01-01 до 9999-12-31 |
Диапазон от време | 00:00:00 до 23:59:59,9999999 | 00:00:00 до 23:59:59,9999999 |
Дължина на знака | Минимум 26 позиции 34 максимум | 19 позиции минимум 27 максимум |
Размер на съхранение | 8 до 10 байта, в зависимост от точността* * Плюс 1 байт за съхраняване на точността | 6 до 8 байта, в зависимост от прецизността* * Плюс 1 байт за съхраняване на точността |
Точност | 100 наносекунди | 100 наносекунди |
Дробна секундна точност | Да | Да |
Дефинирана от потребителя точност на дробна секунда | Да | Да |
Обхват на изместване на часовата зона | -14:00 до +14:00 | Няма |
Осведомяване и запазване на изместването на часовата зона | Да | Не |
Наясно с лятното часово време | Не | Не |
Трябва ли да използвам „datetime2“ или „datetimeoffset“?
Това зависи от това дали трябва да включите изместване на часовата зона.
Ако трябва да включите изместване на часовата зона, тогава ще трябва да използвате datetimeoffset .
Ако не, тогава използвайте datetime2 , тъй като ще спестите място за съхранение и ще премахнете всички потенциални проблеми с (потенциално грешно) изместване на часовата зона във вашите данни.
Пример 1 – Основно сравнение
Ето един бърз пример за демонстриране на основната разлика между datetime2 и datetimeoffset .
DECLARE @thedatetimeoffset datetimeoffset(7), @thedatetime2 datetime2(7); SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30'; SET @thedatetime2 = @thedatetimeoffset; SELECT @thedatetimeoffset AS 'datetimeoffset', @thedatetime2 AS 'datetime2';
Резултат:
+------------------------------------+-----------------------------+ | datetimeoffset | datetime2 | |------------------------------------+-----------------------------| | 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.5555555 | +------------------------------------+-----------------------------+
Тук задавам datetime2 променлива на същата стойност като datetimeoffset променлива. Това води до преобразуването на стойността в datetime2 и след това можем да използваме SELECT
изявление, за да видите стойността на всяка променлива.
И двете променливи използват скала от 7, което означава, че имат 7 знака след десетичната запетая.
Така че в този случай единствената разлика между двете е, че datetimeoffset стойността включва изместването на часовата зона и datetime2 стойността не.
Пример 2 – Промяна на точността
И двата вида ви позволяват да посочите точност (чрез използване на скала между 0 и 7). Следователно е възможно да зададете datetime2 стойност с по-ниска точност от datetimeoffset стойност (и обратно).
Пример:
DECLARE @thedatetimeoffset datetimeoffset(7), @thedatetime2 datetime2(3); SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30'; SET @thedatetime2 = @thedatetimeoffset; SELECT @thedatetimeoffset AS 'datetimeoffset', @thedatetime2 AS 'datetime2';
Резултат:
+------------------------------------+-------------------------+ | datetimeoffset | datetime2 | |------------------------------------+-------------------------| | 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.556 | +------------------------------------+-------------------------+
Тук задавам datetime2 стойност до скала от 3, което означава, че завършва с 3 знака след десетичната запетая вместо 7. В този случай нейните дробни секунди се закръгляват нагоре (тъй като следващата дробна цифра е 5 или по-висока).
Така че можем да видим, че е възможно да получим различна стойност за дата/час в зависимост от частите от секундите, които присвояваме на datetime2 . Това работи и по друг начин (напр. ако преобразуваме от datetime2(7) до datetimeoffset(3) ).
Ако обаче намалим дробната част, не се извършва закръгляне:
DECLARE @thedatetimeoffset datetimeoffset(7), @thedatetime2 datetime2(3); SET @thedatetimeoffset = '2025-05-21 10:15:30.5554444 +07:30'; SET @thedatetime2 = @thedatetimeoffset; SELECT @thedatetimeoffset AS 'datetimeoffset', @thedatetime2 AS 'datetime2';
Резултат:
+------------------------------------+-------------------------+ | datetimeoffset | datetime2 | |------------------------------------+-------------------------| | 2025-05-21 10:15:30.5554444 +07:30 | 2025-05-21 10:15:30.555 | +------------------------------------+-------------------------+
Пример 3 – Задаване на стойности от низови литерали
В предишните примери datetime2 стойността беше присвоена чрез задаване на същата стойност като datetimeoffset стойност. Когато направим това, SQL Server извършва имплицитно преобразуване, за да могат данните да „прилягат“ на новия тип данни.
Също така можем да присвоим същата стойност директно на datetime2 променлива (въпреки че официалната документация не посочва изрично, че приема литерал на низ с отместване на часовата зона):
DECLARE @thedatetimeoffset datetimeoffset(7), @thedatetime2 datetime2(7); SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30'; SET @thedatetime2 = '2025-05-21 10:15:30.5555555 +07:30'; SELECT @thedatetimeoffset AS 'datetimeoffset', @thedatetime2 AS 'datetime2';
Резултат:
+------------------------------------+-----------------------------+ | datetimeoffset | datetime2 | |------------------------------------+-----------------------------| | 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.5555555 | +------------------------------------+-----------------------------+
Пример 4 – Размер за съхранение
datetime2 типът данни използва два байта по-малко място за съхранение от datetimeoffset за дадена прецизност.
datetime2 може да бъде 6, 7 или 8 байта, в зависимост от неговата точност.
отместването на датата и времето може да бъде 8, 9 или 10 байта, в зависимост от неговата точност.
Microsoft заявява, че datetime2 типът също използва 1 допълнителен байт, за да съхрани своята прецизност, в който случай ще използва поне 3 байта повече от smalldatetime .
Това важи и за datetimeoffset (въпреки че не е изрично посочено в документацията на Microsoft).
Това обаче зависи от това дали го съхраняваме в таблица или в променлива и дали го преобразуваме в двоична константа или не.
Ето какво се случва, ако използваме DATALENGTH()
функция за връщане на броя байтове, използвани за всяка от нашите стойности:
DECLARE @thedatetimeoffset datetimeoffset(7), @thedatetime2 datetime2(7); SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30'; SET @thedatetime2 = @thedatetimeoffset; SELECT DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset', DATALENGTH(@thedatetime2) AS 'datetime2';
Резултат
+------------------+-------------+ | datetimeoffset | datetime2 | |------------------+-------------| | 10 | 8 | +------------------+-------------+
Както се очакваше, 10 байта за datetimeoffset и 8 байта за datetime2 .
Но ако ги преобразуваме в varbinary , получаваме следното:
DECLARE @thedatetimeoffset datetimeoffset(7), @thedatetime2 datetime2(7); SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30'; SET @thedatetime2 = @thedatetimeoffset; SELECT DATALENGTH(CAST(@thedatetimeoffset AS varbinary(16))) AS 'datetimeoffset', DATALENGTH(CAST(@thedatetime2 AS varbinary(16))) AS 'datetime2';
Резултат
+------------------+-------------+ | datetimeoffset | datetime2 | |------------------+-------------| | 11 | 9 | +------------------+-------------+
Към всяка стойност се добавя допълнителен байт, за да се съхрани прецизността.
Много разработчици предполагат, че конвертирането в varbinary е представителен за това как SQL Server всъщност съхранява стойности за дата и час. Това обаче е само частично вярно.
Въпреки че е вярно, че SQL Server съхранява своите стойности за дата и час в шестнадесетични, тази шестнадесетична стойност всъщност не включва точността. Това е така, защото точността е включена в дефиницията на колоната. Но когато преобразуваме в varbinary както направихме в предишния пример, точността се добавя преди и това добавя допълнителен байт.
За повече подробности относно това как тези типове данни се съхраняват в различни контексти, вижте следните статии:
- Разбиране на размера на съхранение „datetimeoffset“ в SQL Server
- Разбиране на размера на съхранение „datetime2“ в SQL Server