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

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

Tento článek se zabývá hlavními rozdíly mezi datetime2 a datetimeoffset datové typy na serveru SQL.

Oba datové typy se používají pro ukládání hodnot data a času. Oba jsou velmi podobné, ale s jedním zásadním rozdílem; datetimeoffset ukládá posun časového pásma.

Výsledkem je také datetimeoffset využívá více úložného prostoru než datetime2 , takže byste použili pouze datetimeoffset pokud potřebujete posun časového pásma.

Zde je tabulka, která uvádí hlavní rozdíly mezi těmito dvěma typy.

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

* Plus 1 bajt pro uložení přesnosti

6 až 8 bajtů, v závislosti na přesnosti*

* Plus 1 bajt pro uložení přesnosti

Přesnost 100 nanosekund 100 nanosekund
Zlomková sekundová přesnost Ano Ano
Uživatelsky definovaná přesnost na zlomek sekund Ano Ano
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

Mám použít ‚datetime2‘ nebo ‚datetimeoffset‘?

To závisí na tom, zda potřebujete zahrnout posun časového pásma.

Pokud potřebujete zahrnout posun časového pásma, budete muset použít datetimeoffset .

Pokud ne, použijte datetime2 , protože ušetříte úložný prostor a odstraníte případné problémy s (potenciálně nesprávným) posunem časového pásma ve vašich datech.

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

Zde je rychlý příklad demonstrující základní rozdíl mezi datetime2 a datetimeoffset .

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

Výsledek:

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

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

Obě proměnné používají stupnici 7, což znamená, že mají 7 desetinných míst.

V tomto případě je tedy jediným rozdílem mezi nimi to, že datetimeoffset hodnota zahrnuje posun časového pásma a datetime2 hodnota ne.

Příklad 2 – Změna přesnosti

Oba typy umožňují určit přesnost (pomocí měřítka mezi 0 a 7). Proto je možné nastavit datetime2 s nižší přesností než datetimeoffset hodnotu (a naopak).

Příklad:

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

Výsledek:

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

Zde nastavím datetime2 hodnotu na stupnici 3, což znamená, že skončí se 3 desetinnými místy místo 7. V tomto případě jsou její desetinné sekundy zaokrouhleny nahoru (protože další desetinná číslice je 5 nebo vyšší).

Takže vidíme, že je možné získat jinou hodnotu data/času v závislosti na zlomkových sekundách, které přiřadíme datetime2 . Funguje to i opačným způsobem (např. pokud převedeme z datetime2(7) na datetimeoffset(3) ).

Pokud však zlomkovou část zmenšíme, žádné zaokrouhlení se neprovádí:

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

Výsledek:

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

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

V předchozích příkladech datetime2 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.

Stejnou hodnotu můžeme také přiřadit přímo datetime2 proměnná (i když oficiální dokumentace výslovně neuvádí, že přijímá řetězcový literál s posunem časového pásma):

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

Výsledek:

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

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

datetime2 datový typ využívá o dva bajty menší úložiště než datetimeoffset pro jakoukoli danou přesnost.

datetime2 může mít buď 6, 7 nebo 8 bajtů, v závislosti na jeho přesnosti.

datetimeoffset může mít buď 8, 9 nebo 10 bajtů, v závislosti na jeho přesnosti.

Microsoft uvádí, že datetime2 type také používá 1 bajt navíc k uložení své přesnosti, v takovém případě by použil alespoň o 3 bajty více než smalldatetime .

To platí také pro datetimeoffset (i když to není výslovně uvedeno v dokumentaci společnosti Microsoft).

To však závisí na tom, zda ji ukládáme do tabulky nebo do proměnné a zda ji převádíme na binární konstantu.

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

Výsledek

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

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

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

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

Výsledek

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

Ke každé hodnotě je přidán extra bajt, aby se uložila přesnost.

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. Je to proto, že přesnost je zahrnuta v definici sloupce. Ale když převedeme na varbinary stejně jako v předchozím příkladu je předřazena přesnost, což přidává další bajt.

Další podrobnosti o tom, jak jsou tyto datové typy uloženy v různých kontextech, naleznete v následujících článcích:

  • Porozumění velikosti úložiště „datetimeoffset“ na serveru SQL Server
  • Porozumění velikosti úložiště ‚datetime2‘ na serveru SQL Server

  1. Při mapování sloupce PostgreSQL LTREE v režimu spánku se zobrazuje chyba

  2. Jak přidat cizí klíč do SQL?

  3. 4 způsoby, jak oddělit hodiny, minuty a sekundy od časové hodnoty v MariaDB

  4. Jak spustit stejný dotaz na všech databázích v instanci?