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

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

W tym artykule przyjrzymy się głównym różnicom między datetime2 i przesunięcie daty i godziny typy danych w SQL Server.

Oba typy danych są używane do przechowywania wartości daty i godziny. Oba są bardzo podobne, ale z jedną kluczową różnicą; przesunięcie daty i godziny przechowuje przesunięcie strefy czasowej.

Powoduje to również przesunięcie daty i godziny zużywa więcej miejsca niż datetime2 , więc użyjesz tylko przesunięcie daty i godziny jeśli potrzebujesz przesunięcia strefy czasowej.

Oto tabela przedstawiająca kluczowe różnice między tymi dwoma typami.

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

* Plus 1 bajt do przechowywania precyzji

6 do 8 bajtów, w zależności od precyzji*

* Plus 1 bajt do przechowywania precyzji

Dokładność 100 nanosekund 100 nanosekund
Ułamkowa druga precyzja Tak Tak
Zdefiniowana przez użytkownika precyzja ułamkowa sekundy Tak Tak
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

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

Zależy to od tego, czy musisz uwzględnić przesunięcie strefy czasowej.

Jeśli chcesz uwzględnić przesunięcie strefy czasowej, musisz użyć przesunięcie daty i godziny .

Jeśli nie, użyj datetime2 , ponieważ zaoszczędzisz miejsce na dysku i wyeliminujesz wszelkie potencjalne problemy z (potencjalnie błędnym) przesunięciem strefy czasowej w Twoich danych.

Przykład 1 – Porównanie podstawowe

Oto krótki przykład pokazujący podstawową różnicę między datetime2 i przesunięcie daty i godziny .

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

Wynik:

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

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

Obie zmienne używają skali 7, co oznacza, że ​​mają 7 miejsc po przecinku.

W tym przypadku jedyną różnicą między nimi jest to, że przesunięcie daty i godziny wartość obejmuje przesunięcie strefy czasowej i datetime2 wartość nie.

Przykład 2 – Zmiana precyzji

Oba typy umożliwiają określenie precyzji (przy użyciu skali od 0 do 7). Dlatego możliwe jest ustawienie datetime2 wartość z niższą precyzją niż przesunięcie daty i godziny wartość (i odwrotnie).

Przykład:

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

Wynik:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime2               |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.556 |
+------------------------------------+-------------------------+

Tutaj ustawiam datetime2 wartość do skali 3, co oznacza, że ​​kończy się na 3 miejscach po przecinku zamiast 7. W tym przypadku jego ułamki sekund są zaokrąglane w górę (ponieważ następna cyfra ułamkowa to 5 lub więcej).

Widzimy więc, że możliwe jest uzyskanie różnych wartości daty/czasu w zależności od ułamków sekund, które przypisujemy do datetime2 . Działa to również w drugą stronę (np. jeśli konwertujemy z datetime2(7) na przesunięcie daty i godziny(3) ).

Jeśli jednak zmniejszymy część ułamkową, zaokrąglenie nie zostanie wykonane:

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

Wynik:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime2               |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5554444 +07:30 | 2025-05-21 10:15:30.555 |
+------------------------------------+-------------------------+

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

W poprzednich przykładach datetime2 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.

Możemy również przypisać tę samą wartość bezpośrednio do datetime2 zmienna (mimo że oficjalna dokumentacja nie stwierdza wyraźnie, że akceptuje ona literał ciągu znaków z przesunięciem strefy czasowej):

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

Wynik:

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

Przykład 4 – Rozmiar pamięci

datetime2 typ danych zajmuje o dwa bajty mniej miejsca niż przesunięcie daty i godziny dla dowolnej precyzji.

datetime2 może mieć 6, 7 lub 8 bajtów, w zależności od jego precyzji.

przesunięcie daty i godziny może mieć 8, 9 lub 10 bajtów, w zależności od jego precyzji.

Microsoft twierdzi, że datetime2 type wykorzystuje również 1 dodatkowy bajt w celu przechowywania swojej precyzji, w takim przypadku zużyłby co najmniej 3 bajty więcej niż smalldatetime .

Dotyczy to również przesunięcia daty i godziny (chociaż nie jest to wyraźnie określone w dokumentacji Microsoft).

Zależy to jednak od tego, czy przechowujemy go w tabeli, czy w zmiennej i czy konwertujemy go na stałą binarną.

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), 
  @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';

Wynik

+------------------+-------------+
| datetimeoffset   | datetime2   |
|------------------+-------------|
| 10               | 8           |
+------------------+-------------+

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

Ale jeśli przekonwertujemy je na varbinary , otrzymujemy:

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

Wynik

+------------------+-------------+
| datetimeoffset   | datetime2   |
|------------------+-------------|
| 11               | 9           |
+------------------+-------------+

Do każdej wartości dodawany jest dodatkowy bajt w celu zapisania precyzji.

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 w rzeczywistości nie obejmuje precyzji. Dzieje się tak, ponieważ precyzja jest zawarta w definicji kolumny. Ale kiedy przekonwertujemy na varbinary tak jak w poprzednim przykładzie, precyzja jest poprzedzona, a to dodaje dodatkowy bajt.

Więcej informacji na temat przechowywania tych typów danych w różnych kontekstach można znaleźć w następujących artykułach:

  • Zrozumienie rozmiaru pamięci „datetimeoffset” w SQL Server
  • Zrozumienie rozmiaru pamięci „datetime2” w SQL Server

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak mogę się dowiedzieć, czy zgłoszono wyjątek SQL z powodu naruszenia klucza obcego?

  2. SQL Server — transakcje wycofują się w przypadku błędu?

  3. Rozwiązywanie problemów z brakiem wątków roboczych

  4. Uważaj na tabelę nowych rekordów w bazie danych sql

  5. 7 sposobów na zwrócenie wszystkich tabel z kluczem podstawowym w SQL Server