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.