Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

datetime vs datetimeoffset w SQL Server:jaka jest różnica?

W tym artykule podkreślono główne różnice między data i godziną i przesunięcie daty i godziny typy danych w SQL Server.

Oba typy danych są używane do przechowywania wartości daty i godziny. Ale są między nimi znaczące różnice.

Być może najbardziej oczywistą różnicą jest to, że przesunięcie daty i godziny przechowuje przesunięcie strefy czasowej, podczas gdy data i godzina nie.

Kolejną ważną różnicą jest to, że przesunięcie daty i godziny pozwala określić precyzję (do 7 miejsc po przecinku). Oznacza to, że przesunięcie daty i godziny wartości mogą różnić się rozmiarem pamięci, w zależności od używanej precyzji.

data i godzina z drugiej strony typ ma stały rozmiar i precyzję przechowywania.

Ogólnie rzecz biorąc, należy unikać używania datetime chyba że masz dobry powód, aby z niego korzystać (np. wspieranie starszego systemu). Ponadto datetime2 typ jest bliższy niż przesunięcie daty i godziny , więc lepiej użyć tego, jeśli nie potrzebujesz przesunięcia strefy czasowej.

Tak czy inaczej, oto tabela porównująca data i godzina i przesunięcie daty i godziny :

Funkcja przesunięcie daty i godziny data i godzina
Zgodny z SQL (ANSI i ISO 8601) Tak Nie
Zakres dat 0001-01-01 do 9999-12-31 1753-01-01 do 9999-12-31
Zakres czasu 00:00:00 do 23:59:59.9999999 00:00:00 do 23:59:59,997
Długość znaku 26 pozycji minimum
34 maksimum
Minimalnie 19 pozycji
Maksymalnie 23
Rozmiar pamięci 8 do 10 bajtów, w zależności od precyzji*

* Plus 1 bajt do przechowywania precyzji w niektórych przypadkach. Zobacz poniżej, aby uzyskać więcej informacji.

8 bajtów
Dokładność 100 nanosekund Zaokrąglone do przyrostów o 0,000, 0,003 lub 0,007 sekundy
Zdefiniowana przez użytkownika precyzja ułamkowa sekundy Tak Nie
Zakres przesunięcia strefy czasowej -14:00 do +14:00 Brak
Świadomość i zachowanie przesunięcia strefy czasowej Tak Nie
Świadomość czasu letniego Nie Nie

Przykład 1 – Porównanie podstawowe

W każdym razie, oto krótki przykład pokazujący podstawową różnicę między datetime i przesunięcie daty i godziny .

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';

Wynik:

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

Tutaj ustawiam datę zmienna na taką samą wartość jak przesunięcie daty i godziny zmienny. Powoduje to przekonwertowanie wartości na data/godzina a następnie możemy użyć SELECT oświadczenie, aby zobaczyć wartość każdej zmiennej.

W tym przypadku przesunięcie daty i godziny wartość zawiera przesunięcie strefy czasowej i 7 miejsc po przecinku. data i godzina z drugiej strony wartość nie obejmuje przesunięcia strefy czasowej i ma tylko 3 miejsca po przecinku. Ponadto jego trzecia cyfra ułamkowa jest zaokrąglana w górę. Dzieje się tak, ponieważ jego dokładność jest zawsze zaokrąglana z dokładnością do 0,000, 0,003 lub 0,007 sekundy.

Przykład 2 – ustawianie wartości z literałów łańcuchowych

W poprzednim przykładzie data i godzina wartość została przypisana przez ustawienie jej na taką samą wartość jak przesunięcie daty i godziny wartość. Kiedy to robimy, SQL Server wykonuje niejawną konwersję, aby dane „dopasowały się” do nowego typu danych.

Jeśli spróbujemy przypisać tę samą wartość bezpośrednio do datetime zmienna otrzymujemy błąd:

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';

Wynik:

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

Dzieje się tak, ponieważ data i godzina typ danych nie obsługuje literału ciągu z przesunięciem strefy czasowej. Ponadto nie obsługuje literałów łańcuchowych z więcej niż 3 miejscami po przecinku.

Jeśli więc usuniemy przesunięcie strefy czasowej, ale zachowamy wszystkie ułamki sekund, nadal otrzymamy błąd:

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';

Wynik:

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

Aby to zadziałało, musielibyśmy przypisać wartość z nie więcej niż 3 miejscami po przecinku:

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';

Wynik:

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

Tak czy inaczej, data i godzina zawsze będzie mieć inną wartość niż przesunięcie daty i godziny , ponieważ nie obejmuje przesunięcia strefy czasowej. Będzie to prawdą, nawet jeśli użyjemy tej samej dokładności ułamków sekund i wartości ułamków sekund.

Aby to zademonstrować, oto co się stanie, jeśli przypiszemy tę samą wartość do 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';

Wynik:

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

W tym przypadku przesunięcie daty i godziny używa skali 3, co daje 3 miejsca po przecinku (tak samo jak data-godzina ). Odbywa się to za pomocą datetimeoffset(3) podczas deklarowania zmiennej.

Zmieniłem również ułamki sekund, aby data-godzina nie zaokrągliłby ich w górę (tak, aby obie wartości miały dokładnie tę samą część ułamkową).

Niezależnie od tego przesunięcie daty i godziny nadal dodaje przesunięcie strefy czasowej, ustawione na domyślną wartość +00:00.

Zwróć uwagę, że mój system wyświetla końcowe zera w przesunięciu daty i godziny część ułamkowa, ale wartość używa tylko 3 miejsc po przecinku.

Przykład 3 – Rozmiar pamięci

data i godzina typ danych wykorzystuje 8 bajtów.

przesunięcie daty i godziny typ danych używa 8, 9 lub 10 bajtów, w zależności od jego precyzji.

Dlatego nie oszczędzasz żadnego rozmiaru pamięci, używając datetime .

Jeśli jednak przekonwertujesz przesunięcie daty i godziny wartość do stałej binarnej, dodaje 1 bajt w celu przechowywania precyzji.

Oto, co się stanie, jeśli użyjemy DATALENGTH() funkcja zwracająca liczbę bajtów użytych dla każdej z naszych wartości:

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';

Wynik

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

Zgodnie z oczekiwaniami 10 bajtów dla przesunięcie daty i godziny i 8 bajtów na data i godzina .

Ale jeśli przekonwertujemy je na varbinary , otrzymujemy:

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';

Wynik

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

Dodatkowy bajt jest dodawany do przesunięcia daty i godziny wartość, ale nie do data i godzina wartość. Dzieje się tak, ponieważ przesunięcie daty i godziny value potrzebuje dodatkowego bajtu do przechowywania precyzji (ponieważ precyzja jest zdefiniowana przez użytkownika). data i godzina z drugiej strony wartość ma stałą precyzję, więc nie ma potrzeby przechowywania precyzji z wartością.

Wielu programistów zakłada, że ​​konwersja na varbinary reprezentuje sposób, w jaki SQL Server faktycznie przechowuje wartości daty i godziny. Jest to jednak tylko częściowo prawda.

Chociaż prawdą jest, że SQL Server przechowuje swoje wartości daty i godziny w postaci szesnastkowej, ta wartość szesnastkowa nie obejmuje w rzeczywistości precyzji podczas przechowywania przesunięcie daty i godziny wartości. Dzieje się tak, ponieważ precyzja jest zawarta w definicji kolumny.

Aby uzyskać więcej informacji na temat przechowywania tego typu danych w bazie danych, zobacz Zrozumienie rozmiaru pamięci „datetimeoffset” w SQL Server.

Czy powinienem używać „datetime” czy „datetimeoffset”?

Jeśli chcesz uwzględnić przesunięcie strefy czasowej, musisz użyć przesunięcie daty i godziny . Jeśli nie, to data i godzina może wystarczyć.

Firma Microsoft zaleca jednak korzystanie z datetime2 do nowej pracy, ponieważ ma wiele zalet w porównaniu z datetime .

Zobacz datetime vs datetime2 dla porównania tych typów danych.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Uwagi na temat edycji SQL Server 2019

  2. Zero impasu SQL z założenia - jakieś wzorce kodowania?

  3. Implementacja wspólnego wskaźnika wydajności MS SQL Server

  4. INSTR() odpowiednik w SQL Server

  5. Jak mogę wstawić 10 milionów rekordów w najkrótszym możliwym czasie?