Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

datetime2 vs datetimeoffset dans SQL Server :quelle est la différence ?

Cet article examine les principales différences entre le datetime2 et datetimeoffset types de données dans SQL Server.

Les deux types de données sont utilisés pour stocker les valeurs de date et d'heure. Les deux sont très similaires, mais avec une différence essentielle ; le datetimeoffset stocke le décalage horaire.

Cela entraîne également datetimeoffset utilisant plus d'espace de stockage que datetime2 , vous n'utiliserez donc que datetimeoffset si vous avez besoin du décalage horaire.

Voici un tableau qui décrit les principales différences entre ces deux types.

Fonctionnalité datetimeoffset datetime2
Conformité SQL (ANSI et ISO 8601) Oui Oui
Plage de dates 0001-01-01 à 9999-12-31 0001-01-01 à 9999-12-31
Plage de temps 00:00:00 à 23:59:59.9999999 00:00:00 à 23:59:59.9999999
Longueur des caractères 26 postes minimum
34 maximum
19 postes minimum
27 maximum
Taille de stockage 8 à 10 octets, selon la précision*

* Plus 1 octet pour stocker la précision

6 à 8 octets, selon la précision*

* Plus 1 octet pour stocker la précision

Précision 100 nanosecondes 100 nanosecondes
Précision fractionnaire de seconde Oui Oui
Précision fractionnaire de seconde définie par l'utilisateur Oui Oui
Plage de décalage de fuseau horaire -14h00 à +14h00 Aucun
Conscience et préservation du décalage horaire Oui Non
Respect de l'heure d'été Non Non

Dois-je utiliser "datetime2" ou "datetimeoffset" ?

Cela dépend si vous devez ou non inclure un décalage de fuseau horaire.

Si vous devez inclure un décalage de fuseau horaire, vous devrez utiliser datetimeoffset .

Sinon, utilisez datetime2 , car vous économiserez de l'espace de stockage et éliminerez tout problème potentiel lié à un décalage de fuseau horaire (potentiellement erroné) dans vos données.

Exemple 1 - Comparaison de base

Voici un exemple rapide pour démontrer la différence fondamentale entre datetime2 et 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';

Résultat :

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

Ici, j'ai mis un datetime2 variable à la même valeur que datetimeoffset variable. Cela entraîne la conversion de la valeur en datetime2 et nous pouvons alors utiliser un SELECT instruction pour voir la valeur de chaque variable.

Les deux variables utilisent une échelle de 7, ce qui signifie qu'elles ont 7 décimales.

Donc, dans ce cas, la seule différence entre les deux est que le datetimeoffset la valeur inclut le décalage du fuseau horaire et la datetime2 la valeur ne le fait pas.

Exemple 2 - Modification de la précision

Les deux types vous permettent de spécifier une précision (en utilisant une échelle entre 0 et 7). Par conséquent, il est possible de définir la datetime2 valeur à une précision inférieure à datetimeoffset valeur (et inversement).

Exemple :

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

Résultat :

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

Ici, je mets le datetime2 valeur sur une échelle de 3, ce qui signifie qu'elle se retrouve avec 3 décimales au lieu de 7. Dans ce cas, ses fractions de seconde sont arrondies (car le prochain chiffre fractionnaire est 5 ou plus).

Nous pouvons donc voir qu'il est possible d'obtenir une valeur de date/heure différente en fonction des fractions de secondes que nous attribuons à datetime2 . Cela fonctionne également dans l'autre sens (par exemple, si nous convertissons à partir de datetime2(7) à datetimeoffset(3) ).

Cependant, si nous réduisons la partie fractionnaire, aucun arrondi n'est effectué :

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

Résultat :

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

Exemple 3 - Définition de valeurs à partir de littéraux de chaîne

Dans les exemples précédents, le datetime2 la valeur a été attribuée en la définissant sur la même valeur que datetimeoffset valeur. Lorsque nous faisons cela, SQL Server effectue une conversion implicite afin que les données « correspondent » au nouveau type de données.

Nous pouvons également attribuer la même valeur directement à la datetime2 variable (même si la documentation officielle n'indique pas explicitement qu'elle accepte un littéral de chaîne avec un décalage de fuseau horaire) :

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

Résultat :

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

Exemple 4 - Taille de stockage

Le datetime2 le type de données utilise deux octets de stockage en moins que datetimeoffset pour une précision donnée.

Le datetime2 peut être de 6, 7 ou 8 octets, selon sa précision.

Le datetimeoffset peut être de 8, 9 ou 10 octets, selon sa précision.

Microsoft déclare que le datetime2 type utilise également 1 octet supplémentaire afin de stocker sa précision, auquel cas il utiliserait au moins 3 octets de plus que smalldatetime .

Cela s'applique également à datetimeoffset (même si ce n'est pas explicitement indiqué dans la documentation Microsoft).

Cependant, cela dépend si nous le stockons dans une table ou dans une variable, et si nous le convertissons ou non en une constante binaire.

Voici ce qui se passe si nous utilisons le DATALENGTH() fonction pour retourner le nombre d'octets utilisés pour chacune de nos valeurs :

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

Résultat

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

Comme prévu, 10 octets pour datetimeoffset et 8 octets pour datetime2 .

Mais si nous les convertissons en varbinary , nous obtenons ceci :

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

Résultat

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

Un octet supplémentaire est ajouté à chaque valeur afin de stocker la précision.

De nombreux développeurs supposent que la conversion en varbinary est représentatif de la manière dont SQL Server stocke réellement les valeurs de date et d'heure. Cependant, ce n'est que partiellement vrai.

S'il est vrai que SQL Server stocke ses valeurs de date et d'heure au format hexadécimal, cette valeur hexadécimale n'inclut pas réellement la précision. En effet, la précision est incluse dans la définition de la colonne. Mais lorsque nous convertissons en varbinary comme nous l'avons fait dans l'exemple précédent, la précision est ajoutée, ce qui ajoute un octet supplémentaire.

Pour plus de détails sur la manière dont ces types de données sont stockés dans différents contextes, consultez les articles suivants :

  • Comprendre la taille de stockage "datetimeoffset" dans SQL Server
  • Comprendre la taille de stockage "datetime2" dans SQL Server