Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

datetime срещу datetimeoffset в SQL Server:Каква е разликата?

Тази статия подчертава основните разлики между дата и час и datetimeoffset типове данни в SQL Server.

И двата типа данни се използват за съхранение на стойности за дата и час. Но има значителни разлики между двете.

Може би най-очевидната разлика е, че datetimeoffset съхранява изместването на часовата зона, докато datetime не прави

Друга важна разлика е отместването на датата и времето ви позволява да зададете точността (до 7 знака след десетичната запетая). Това означава, че datetimeoffset стойностите могат да варират в размера на съхранението си, в зависимост от използваната прецизност.

Дата и час тип, от друга страна, има фиксиран размер и прецизност.

Като цяло трябва да избягвате използването на datetime освен ако нямате основателна причина да го използвате (като поддръжка на наследена система). Също така, datetime2 типът е по-близък от datetimeoffset , така че е по-добре да го използвате, ако не се нуждаете от изместване на часовата зона.

Така или иначе, ето таблица, която сравнява дата и час и datetimeoffset :

Функция datetimeoffset дата и час
Съвместим с SQL (ANSI и ISO 8601) Да Не
Период от време 0001-01-01 до 9999-12-31 1753-01-01 до 9999-12-31
Диапазон от време 00:00:00 до 23:59:59,9999999 00:00:00 до 23:59:59,997
Дължина на знака Минимум 26 позиции
34 максимум
19 позиции минимум
23 максимум
Размер на съхранение 8 до 10 байта, в зависимост от точността*

* Плюс 1 байт за съхраняване на точността в някои случаи. Вижте по-долу за повече информация.

8 байта
Точност 100 наносекунди Закръглено до стъпки от .000, .003 или .007 секунди
Дефинирана от потребителя точност на дробна секунда Да Не
Обхват на изместване на часовата зона -14:00 до +14:00 Няма
Осведомяване и запазване на изместването на часовата зона Да Не
Наясно с лятното часово време Не Не

Пример 1 – Основно сравнение

Във всеки случай, ето един бърз пример за демонстриране на основната разлика между дата и час и datetimeoffset .

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Резултат:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.557 |
+------------------------------------+-------------------------+

Тук задавам дата и час променлива на същата стойност като datetimeoffset променлива. Това води до преобразуване на стойността в datetime и след това можем да използваме SELECT изявление, за да видите стойността на всяка променлива.

В този случай datetimeoffset стойността включва изместването на часовата зона и 7 знака след десетичната запетая. Дата и час стойност от друга страна, не включва изместването на часовата зона и има само 3 знака след десетичната запетая. Освен това третата му дробна цифра се закръглява нагоре. Това е така, защото неговата точност винаги се закръглява до стъпки от .000, .003 или .007 секунди.

Пример 2 – Задаване на стойности от низови литерали

В предишния пример, datetime стойността беше присвоена чрез задаване на същата стойност като datetimeoffset стойност. Когато направим това, SQL Server извършва имплицитно преобразуване, за да могат данните да „прилягат“ на новия тип данни.

Ако се опитаме да присвоим същата стойност директно на datetime променлива получаваме грешка:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555 +07:30';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Резултат:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Това е така, защото datetime типът данни не поддържа низов литерал с изместване на часовата зона. Освен това не поддържа низови литерали с повече от 3 знака след десетичната запетая.

Така че, ако премахнем изместването на часовата зона, но запазим всички частични секунди, пак ще получим грешка:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Резултат:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

За да работи, ще трябва да зададем стойност с не повече от 3 знака след десетичната запетая:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Резултат:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.557 |
+------------------------------------+-------------------------+

Така или иначе, дата и час винаги ще съдържа различна стойност на datetimeoffset , защото не включва изместването на часовата зона. Това ще бъде вярно, дори ако използваме същата точност на дробни секунди и стойност на дробни секунди.

За да демонстрираме това, ето какво се случва, ако присвоим същата стойност на datetimeoffset :

DECLARE 
  @thedatetimeoffset datetimeoffset(3), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.123';
SET @thedatetime = '2025-05-21 10:15:30.123';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Резултат:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.1230000 +00:00 | 2025-05-21 10:15:30.123 |
+------------------------------------+-------------------------+

В този случай datetimeoffset използва скала от 3, което му дава 3 знака след десетичната запетая (същото като datetime ). Това се прави с помощта на datetimeoffset(3) при деклариране на променливата.

Също така промених частичните секунди, така че datetime няма да ги закръгли нагоре (така че и двете стойности споделят точно една и съща дробна част).

Независимо от това, datetimeoffset все още добавя изместване на часовата зона, зададено на стойността по подразбиране +00:00.

Имайте предвид, че моята система показва нули в края на datetimeoffset е дробна част, но стойността използва само 3 знака след десетичната запетая.

Пример 3 – Размер за съхранение

Дата и час типът данни използва 8 байта.

отместването на датата и времето типът данни използва 8, 9 или 10 байта, в зависимост от неговата точност.

Следователно не запазвате никакъв размер на хранилището, като използвате datetime .

Въпреки това, ако конвертирате datetimeoffset стойност към двоична константа, тя добавя 1 байт, за да запази точността.

Ето какво се случва, ако използваме DATALENGTH() функция за връщане на броя байтове, използвани за всяка от нашите стойности:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset',
  DATALENGTH(@thedatetime) AS 'datetime';

Резултат

+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 10               | 8          |
+------------------+------------+

Както се очакваше, 10 байта за datetimeoffset и 8 байта за дата и час .

Но ако ги преобразуваме в varbinary , получаваме следното:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(CAST(@thedatetimeoffset AS varbinary(16))) AS 'datetimeoffset',
  DATALENGTH(CAST(@thedatetime AS varbinary(16))) AS 'datetime';

Резултат

+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 11               | 8          |
+------------------+------------+

Допълнителен байт се добавя към datetimeoffset стойност, но не до дата и час стойност. Това е така, защото datetimeoffset value се нуждае от допълнителен байт за съхраняване на точността (тъй като точността е дефинирана от потребителя). Дата и час стойността от друга страна има фиксирана точност, така че няма нужда точността да се съхранява със стойността.

Много разработчици приемат, че конвертирането в varbinary е представителен за това как SQL Server всъщност съхранява стойности за дата и час. Това обаче е само частично вярно.

Въпреки че е вярно, че SQL Server съхранява своите стойности за дата и час в шестнадесетични, тази шестнадесетична стойност всъщност не включва прецизността при съхраняване на datetimeoffset стойности. Това е така, защото точността е включена в дефиницията на колоната.

За повече подробности относно това как този тип данни се съхранява в базата данни, вижте Разбиране на размера на съхранение „datetimeoffset“ в SQL Server.

Трябва ли да използвам „datetime“ или „datetimeoffset“?

Ако трябва да включите изместване на часовата зона, тогава ще трябва да използвате datetimeoffset . Ако не, тогава дата и час може да е достатъчно.

Въпреки това Microsoft препоръчва да използвате datetime2 за нова работа, тъй като има много предимства пред datetime .

Вижте datetime срещу datetime2 за сравнение на тези типове данни.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Кодиране на символи по подразбиране на SQL Server

  2. Основи на автоматизацията на задачите на SQL Server

  3. Връщане на номера на дял за всеки ред при запитване на разделена таблица в SQL Server (T-SQL)

  4. Как се създава булево поле да/не в SQL сървър?

  5. Естествено присъединяване в SQL Server