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

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

Cet article met en évidence les principales différences entre le datetime 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. Mais il existe des différences importantes entre les deux.

La différence la plus évidente est peut-être que le datetimeoffset stocke le décalage du fuseau horaire, alors que datetime n'a pas.

Une autre différence importante est que datetimeoffset permet de spécifier la précision (jusqu'à 7 décimales). Cela signifie que datetimeoffset les valeurs peuvent varier dans leur taille de stockage, selon la précision utilisée.

La dateheure type, d'autre part, a une taille de stockage et une précision fixes.

Généralement, vous devriez éviter d'utiliser datetime sauf si vous avez une bonne raison de l'utiliser (comme la prise en charge d'un système hérité). En outre, le datetime2 type est plus proche que datetimeoffset , il est donc préférable de l'utiliser si vous n'avez pas besoin d'un décalage de fuseau horaire.

Quoi qu'il en soit, voici un tableau qui compare datetime et datetimeoffset :

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

* Plus 1 octet pour stocker la précision dans certains cas. Voir ci-dessous pour plus d'informations.

8 octets
Précision 100 nanosecondes Arrondi à des incréments de .000, .003 ou .007 secondes
Précision fractionnaire de seconde définie par l'utilisateur Oui Non
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

Exemple 1 - Comparaison de base

Dans tous les cas, voici un exemple rapide pour démontrer la différence fondamentale entre datetime et 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';

Résultat :

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

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

Dans ce cas, le datetimeoffset La valeur inclut le décalage horaire et 7 décimales. La dateheure d'autre part, n'inclut pas le décalage de fuseau horaire et n'a que 3 décimales. De plus, son troisième chiffre fractionnaire est arrondi. En effet, sa précision est toujours arrondie à des incréments de 0,000, 0,003 ou 0,007 secondes.

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

Dans l'exemple précédent, le datetime 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.

Si nous essayons d'attribuer la même valeur directement à la datetime variable nous obtenons une erreur :

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

Résultat :

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

C'est parce que le datetime Le type de données ne prend pas en charge un littéral de chaîne avec un décalage de fuseau horaire. De plus, il ne prend pas en charge les littéraux de chaîne avec plus de 3 décimales.

Donc, si nous supprimons le décalage du fuseau horaire, mais conservons toutes les fractions de seconde, nous aurons toujours une erreur :

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

Résultat :

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

Pour que cela fonctionne, nous aurions besoin d'attribuer une valeur avec pas plus de 3 décimales :

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

Résultat :

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

Quoi qu'il en soit, datetime contiendra toujours une valeur différente de datetimeoffset , car il n'inclut pas le décalage horaire. Cela sera vrai même si nous utilisons la même précision en fraction de seconde et la même valeur en fraction de seconde.

Pour le démontrer, voici ce qui se passe si nous attribuons la même valeur à 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';

Résultat :

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

Dans ce cas datetimeoffset utilise une échelle de 3, ce qui lui donne 3 décimales (identique à datetime ). Ceci est fait en utilisant datetimeoffset(3) lors de la déclaration de la variable.

J'ai également changé les fractions de seconde pour que datetime ne les arrondirait pas (afin que les deux valeurs partagent exactement la même partie fractionnaire).

Quoi qu'il en soit, datetimeoffset ajoute toujours un décalage de fuseau horaire, défini sur sa valeur par défaut de +00:00.

Notez que mon système affiche des zéros de fin sur datetimeoffset est une partie fractionnaire, mais la valeur n'utilise que 3 décimales.

Exemple 3 – Taille de stockage

La dateheure le type de données utilise 8 octets.

Le datetimeoffset Le type de données utilise 8, 9 ou 10 octets, selon sa précision.

Par conséquent, vous n'économisez aucune taille de stockage en utilisant datetime .

Cependant, si vous convertissez un datetimeoffset valeur à une constante binaire, il ajoute 1 octet afin de stocker la précision.

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

Résultat

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

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

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

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

Résultat

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

Un octet supplémentaire est ajouté au datetimeoffset valeur mais pas à la datetime valeur. C'est parce que le datetimeoffset value a besoin d'un octet supplémentaire pour stocker la précision (car la précision est définie par l'utilisateur). La dateheure la valeur, d'autre part, a une précision fixe, il n'est donc pas nécessaire que la précision soit stockée avec la valeur.

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 lors du stockage de datetimeoffset valeurs. En effet, la précision est incluse dans la définition de la colonne.

Pour plus de détails sur la façon dont ce type de données est stocké dans la base de données, consultez Comprendre la taille de stockage « datetimeoffset » dans SQL Server.

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

Si vous devez inclure un décalage de fuseau horaire, vous devrez utiliser datetimeoffset . Si non, alors datetime peut suffire.

Cependant, Microsoft vous recommande d'utiliser datetime2 pour un nouveau travail, car il présente de nombreux avantages par rapport à datetime .

Voir datetime vs datetime2 pour une comparaison sur ces types de données.