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