sql >> Databáze >  >> RDS >> Sqlserver

datetime vs datetimeoffset v SQL Server:Jaký je rozdíl?

Tento článek zdůrazňuje hlavní rozdíly mezi datem a časem a datetimeoffset datové typy na serveru SQL.

Oba datové typy se používají pro ukládání hodnot data a času. Mezi těmito dvěma jsou ale značné rozdíly.

Snad nejviditelnější rozdíl je v tom, že datetimeoffset ukládá posun časového pásma, zatímco datum a čas ne

Dalším důležitým rozdílem je datetimeoffset umožňuje zadat přesnost (až na 7 desetinných míst). To znamená, že datetimeoffset hodnoty se mohou lišit velikostí úložiště v závislosti na použité přesnosti.

datum a čas typ na druhé straně má pevnou velikost úložiště a přesnost.

Obecně byste se neměli používat datetime pokud nemáte dobrý důvod ji používat (např. podpora staršího systému). Také datetime2 type je bližší shoda než datetimeoffset , takže pokud nepotřebujete posun časového pásma, je lepší ho použít.

Ať tak či onak, zde je tabulka, která porovnává datum a čas a datetimeoffset :

Funkce datetimeoffset datum a čas
Vyhovující SQL (ANSI &ISO 8601) Ano Ne
Časové období 0001-01-01 až 9999-12-31 1753-01-01 až 9999-12-31
Časový rozsah 00:00:00 až 23:59:59,9999999 00:00:00 až 23:59:59.997
Délka znaků Minimálně 26 pozic
Maximálně 34
Minimálně 19 pozic
Maximálně 23
Velikost úložiště 8 až 10 bajtů, v závislosti na přesnosti*

* Plus 1 bajt pro uložení přesnosti v některých případech. Další informace naleznete níže.

8 bajtů
Přesnost 100 nanosekund Zaokrouhleno na přírůstky 0,000, 003 nebo 007 sekund
Uživatelsky definovaná přesnost na zlomek sekund Ano Ne
Rozsah posunu časového pásma -14:00 až +14:00 Žádné
Sledování a zachování posunu časového pásma Ano Ne
Sledování letního času Ne Ne

Příklad 1 – Základní srovnání

V každém případě je zde rychlý příklad, který demonstruje základní rozdíl mezi datetime a 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';

Výsledek:

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

Zde nastavím datum a čas proměnnou na stejnou hodnotu jako datetimeoffset variabilní. To způsobí, že se hodnota převede na datetime a pak můžeme použít SELECT pro zobrazení hodnoty každé proměnné.

V tomto případě datetimeoffset hodnota zahrnuje posun časového pásma a 7 desetinných míst. datum a čas hodnota na druhé straně nezahrnuje posun časového pásma a má pouze 3 desetinná místa. Navíc se jeho třetí desetinná číslice zaokrouhluje nahoru. Je to proto, že jeho přesnost je vždy zaokrouhlena na přírůstky 0,000, 003 nebo 0,007 sekund.

Příklad 2 – Nastavení hodnot z řetězcových literálů

V předchozím příkladu datetime hodnota byla přiřazena nastavením na stejnou hodnotu jako datetimeoffset hodnota. Když to uděláme, SQL Server provede implicitní převod, aby data „seděla“ novému datovému typu.

Pokud se pokusíme přiřadit stejnou hodnotu přímo datetime proměnné, dostaneme chybu:

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

Výsledek:

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

Důvodem je datum a čas datový typ nepodporuje řetězcový literál s posunem časového pásma. Také nepodporuje řetězcové literály s více než 3 desetinnými místy.

Pokud tedy odstraníme posun časového pásma, ale zachováme všechny zlomkové sekundy, stále se zobrazí chyba:

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

Výsledek:

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

Aby to fungovalo, museli bychom přiřadit hodnotu s maximálně 3 desetinnými místy:

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

Výsledek:

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

V každém případě datum a čas bude vždy obsahovat jinou hodnotu než datetimeoffset , protože nezahrnuje posun časového pásma. To bude platit, i když použijeme stejnou přesnost ve zlomcích sekund a stejnou hodnotu ve zlomcích sekund.

Abychom to demonstrovali, zde je uvedeno, co se stane, když stejnou hodnotu přiřadíme 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';

Výsledek:

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

V tomto případě datetimeoffset používá stupnici 3, která dává 3 desetinná místa (stejně jako datetime ). To se provádí pomocí datetimeoffset(3) při deklaraci proměnné.

Změnil jsem také zlomkové sekundy tak, aby datum a čas nezaokrouhlí nahoru (takže obě hodnoty sdílejí přesně stejnou zlomkovou část).

Bez ohledu na to, datetimeoffset stále přidává posun časového pásma, nastavený na výchozí hodnotu +00:00.

Všimněte si, že můj systém zobrazuje koncové nuly na datetimeoffset 's zlomkovou částí, ale hodnota používá pouze 3 desetinná místa.

Příklad 3 – Velikost úložiště

datum a čas datový typ používá 8 bajtů.

datetimeoffset datový typ používá buď 8, 9 nebo 10 bajtů, v závislosti na jeho přesnosti.

Použitím datetime tedy neušetříte žádnou velikost úložiště .

Pokud však převedete datetimeoffset hodnotu k binární konstantě, přidá 1 bajt, aby se uložila přesnost.

Zde je to, co se stane, když použijeme DATALENGTH() funkce, která vrátí počet bajtů použitých pro každou z našich hodnot:

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

Výsledek

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

Podle očekávání 10 bajtů pro datetimeoffset a 8 bajtů pro datum a čas .

Pokud je ale převedeme na varbinární , dostaneme následující:

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

Výsledek

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

Do datetimeoffset je přidán další bajt hodnotu, ale ne na datetime hodnota. Důvodem je datetimeoffset hodnota potřebuje další bajt k uložení přesnosti (protože přesnost je definována uživatelem). datum a čas hodnota na druhé straně má pevnou přesnost, takže není potřeba přesnost ukládat s hodnotou.

Mnoho vývojářů předpokládá, že převod na varbinary je reprezentativní pro to, jak SQL Server skutečně ukládá hodnoty data a času. To je však pravda jen částečně.

I když je pravda, že SQL Server ukládá své hodnoty data a času v šestnáctkové soustavě, tato hexadecimální hodnota ve skutečnosti nezahrnuje přesnost při ukládání datetimeoffset hodnoty. Je to proto, že přesnost je zahrnuta v definici sloupce.

Další podrobnosti o tom, jak je tento datový typ uložen v databázi, naleznete v části Vysvětlení velikosti úložiště ‚datetimeoffset‘ na serveru SQL.

Mám použít „datetime“ nebo „datetimeoffset“?

Pokud potřebujete zahrnout posun časového pásma, budete muset použít datetimeoffset . Pokud ne, pak datetime může stačit.

Společnost Microsoft však doporučuje použít datetime2 pro novou práci, protože má mnoho výhod oproti datetime .

Porovnání těchto typů dat naleznete v tématu datetime vs datetime2.


  1. SQL LocalDB vs SQL Server CE

  2. Problém s pamětí SQLite s přístupem singleton

  3. Django Migrations:Primer

  4. PARSE() vs TRY_PARSE() v SQL Server:Jaký je rozdíl?