Quel est un cas d'utilisation valide pour l'utilisation de TIMESTAMP WITHOUT TIME ZONE?

41

Il existe une réponse longue et assez élucidante sur les différences entre

  • TIMESTAMP WITH TIME ZONE -contre-
  • TIMESTAMP WITHOUT TIME ZONE

disponible dans cet article SO . Ce que je voudrais savoir, c’est: existe-t-il des cas d’utilisation valables pour une utilisation effective TIMESTAMP WITHOUT TIME ZONEou faut-il en faire un anti-pattern?

Marcus Junius Brutus
la source
Cette question risque d’être fermée, car elle est "essentiellement basée sur les opinions". J'ai essayé de donner quelques points de vue objectifs dans ma réponse ci-dessous.
Colin 't Hart
2
Ce problème est assez réel, chaque type de données ayant une signification très différente. Je ne considérerais donc certainement pas cette question comme principalement fondée sur une opinion.
Basil Bourque

Réponses:

30

Ceci est indiqué dans de nombreux endroits, mais je pense qu'il est toujours utile de mentionner quand on compare les types timestamp with time zoneavec timestamp without time zone: le timestamp WITH time zonene stocke pas les informations de fuseau horaire avec l'horodatage . Ce que cela fait est de stocker toutes les données dans le fuseau horaire UTC, comme indiqué dans la documentation :

Pour les horodatages avec fuseau horaire, la valeur stockée en interne est toujours en UTC (heure coordonnée universelle, généralement appelée heure moyenne de Greenwich, GMT). Une valeur d'entrée pour laquelle un fuseau horaire est spécifié est convertie en UTC à l'aide du décalage approprié pour ce fuseau horaire. Si aucun fuseau horaire n'est indiqué dans la chaîne d'entrée, il est supposé être dans le fuseau horaire indiqué par le paramètre TimeZone du système et est converti en UTC en utilisant le décalage du fuseau horaire.

Il est considéré comme valide pour certains à utiliser timestamp WITHOUT time zonedans des situations où (1) tout se trouve dans le même fuseau horaire ou (2) que la couche d’application gère le fuseau horaire et ne stocke que tout dans un certain fuseau horaire (généralement UTC). Mais cela est également considéré comme un anti-motif, simple car la solution correcte pour (1) consiste à configurer le paramètre TimeZone sur le fuseau horaire donné pour le système et (2) est déjà résolu, car PostgreSQL enregistre déjà tout sur le même fuseau horaire. (UTC).

Maintenant, avec ces deux bas, je peux venir avec une seule bonne raison d'utiliser timestamp WITHOUT time zone. C'est à ce moment-là que vous souhaitez stocker des événements dans le futur et qu'une sorte d'alerte doit être déclenchée lorsque nous sommes arrivés à cette heure. Cela pourrait être utile timestamp WITH time zonesi et seulement si les règles définies par les lois de la région concernant le fuseau horaire ne changeaient jamais. La règle la plus courante qui change concerne l’adoption ou non de l’heure avancée.

Par exemple, imaginons que vous êtes en train (par exemple, 2013-06-15pas encore à l'heure d'été) de programmer un événement à 2013-01-15 10:00(qui serait déjà en heure d'été), et que 2013-06-15votre région a été désignée pour adopter l'heure d'été; mais quelque temps après cela, le gouvernement a changé la règle et a déclaré que votre région n'utilisera plus l'heure d'été, et que l'heure programmée devient 2013-01-15 11:00(au lieu de 10:00) celle que vous utiliserez si vous utilisez timestamp WITH time zoneet maintenez vos configurations TZ à jour. Bien sûr, vous remarquerez peut-être qu'il est également possible de traiter de tels cas avec le fuseau horaire, si vous suivez les changements de règles dans les régions / fuseaux horaires qui vous intéressent et mettez à jour les enregistrements concernés.

Il est à noter que certaines régions modifient souvent ces règles (comme au Brésil, certains États - mais pas tout le pays - changent souvent), mais dans la plupart des cas, cela change très tôt, afin que vos utilisateurs ne soient affectés que par des événements très éloignés. l'heure actuelle.

Cela dit, je n’ai qu’une suggestion de plus. Si vous avez des utilisateurs, des journaux ou quoi que ce soit sur des fuseaux horaires différents, stockez le fuseau horaire d'où ils viennent et choisissez et utilisez-le timestamp with time zone. De cette façon, vous pouvez (1) traverser des événements se produisant plus proches les uns des autres pour différentes sources (indépendamment de leur fuseau horaire) et (2) afficher l'heure d'origine (l'heure de l'horloge) à laquelle l'événement s'est produit.

MatheusOl
la source
Vous dites: "Je ne peux venir que pour une seule bonne raison d'utiliser l'horodatage avec fuseau horaire". Si ce n'est pas une faute de frappe, êtes-vous en train de suggérer que "l'horodatage sans fuseau horaire" est en fait plus approprié / moins susceptible de produire des malentendus que "horodatage avec fuseau horaire"? Cela me semble contre-intuitif.
Marcus Junius Brutus
@MarcusJuniusBrutus, désolée pour ça, c'était en fait une faute de frappe et je pensais l'inverse ... Vérifiez la réponse modifiée.
MatheusOl
codeblog.jonskeet.uk/2019/03/27/… discute en profondeur ce scénario de règles d'événement futur (avec la même conclusion)
Beni Cherniavsky-Paskin
19

Oui. Il existe des cas d'utilisation pour TIMESTAMP WITHOUT TIME ZONE.

  • Dans les applications d'entreprise courantes, ce type ne serait utilisé que pour:
    • Réservation de rendez-vous futurs
    • Représenter la même heure du jour sur plusieurs fuseaux horaires, comme le 23 à midi à Tokyo et à Paris (deux moments différents à une heure d'intervalle, même heure du jour)
  • Pour les moments de suivi, utilisez des points spécifiques sur la timeline TIMESTAMP WITH TIME ZONE, pas WITHOUT.

TIMESTAMP WITHOUT TIME ZONEles valeurs ne sont pas un point sur la timeline, pas des moments réels. Ils représentent une idée approximative des moments potentiels , des points possibles sur la timeline sur une plage d’environ 26 à 27 heures (la plage des fuseaux horaires dans le monde). Ils n'ont aucune signification réelle jusqu'à ce que vous appliquiez un fuseau horaire ou un décalage par rapport à UTC .

Ex: Noël

Par exemple, supposons que vous deviez enregistrer le début des vacances / jours saints.

Table: holiday_

Column: year_         Type: SMALLINT
Column: description_  Type: VARCHAR
Column: start_        Type: TIMESTAMP WITHOUT TIME ZONE

Pour enregistrer le fait que Noël commence après minuit le 25 décembre de cette année, nous devons dire 2016-12-25 00:00:00sans fuseau horaire. Au début de la journée du père Noël, il se rend à Auckland en Nouvelle-Zélande juste après minuit, car il s'agit de l'un des tout premiers mid-night du monde. Ensuite, il se dirige vers l’Ouest, comme à l’heure suivante, pour atteindre bientôt les Philippines. Ensuite, les rennes se dirigent vers l’ouest pour atteindre l’Inde à minuit, plusieurs heures après celle d’Auckland. Beaucoup plus tard, il est toujours minuit à Paris FR et encore plus tard minuit à Montréal, en Californie. Toutes ces visites du père Noël ont lieu à des moments différents , mais toutes se sont déroulées peu de temps après minuit, par minuit propre à chaque localité.

Donc, enregistrer 2016-12-25 00:00:00sans le fuseau horaire que le début de Noël est informatif et légitime, mais seulement vaguement. Jusqu'à ce que vous disiez «Noël à Auckland» ou «Noël à Montréal», nous n'avons pas de moment précis dans le temps. Si vous enregistrez le moment réel à chaque fois que le traîneau touche le sol, vous utiliserez TIMESTAMP WITH TIME ZONEplutôt que le WITHOUTtype.

Semblable à Noël, c'est le réveillon du nouvel an. Lorsque le Times Square Ball tombe à New York , les habitants de Seattle gardent toujours leur champagne au froid et préparent leurs cornes de fête . Pourtant, nous enregistrons l' idée du moment du Nouvel An comme 2017-01-01 00:00:00dans un TIMESTAMP WITHOUT TIME ZONE. En revanche, si nous voulons enregistrer quand le ballon est tombé à New York ou quand les habitants de Seattle s’essoufflent, nous utiliserons TIMESTAMP WITH TIME ZONE(non WITHOUT) pour enregistrer ces moments réels, à trois heures d’écart l'un de l'autre.

Ex: déplacements d'usine

Un autre exemple pourrait consister à enregistrer une politique qui implique une heure fixe sur différents emplacements. Supposons que nous ayons des usines à Détroit, Düsseldorf et Delhi. Si nous disons que dans les trois usines, le premier quart de travail commence à 6 heures du matin et la pause du déjeuner à 11h30, cela pourrait être enregistré comme TIMESTAMP WITHOUT TIME ZONE. Encore une fois, cette information est utile de manière vague mais n'indique pas un moment précis avant l'application d'un fuseau horaire. Un nouveau jour se lève plus tôt dans l'est. L’usine de Delhi sera donc la première à ouvrir à 6 heures du matin. Quelques heures plus tard, l’usine de Düsseldorf commence à travailler à 6 heures du matin. Mais l’usine de Detroit n’ouvrira réellement que six heures plus tard, au plus tard à 6 heures.

Comparez cette idée (du début de l'équipe d'usine en général) au fait historique de savoir quand chaque ouvrier d'usine a commencé à effectuer son service un jour donné. Le chronométrage est un moment réel, un point réel sur la timeline. Nous enregistrons donc cela dans une colonne de type TIMESTAMP WITH TIME ZONEplutôt que de WITHOUTtype.

Donc, oui, il existe des cas d'utilisation légitimes pour TIMESTAMP WITHOUT TIME ZONE. Mais d'après mon expérience avec les applications professionnelles, elles sont relativement rares. En affaires, nous avons tendance à nous soucier des moments réels: quand la facture est-elle réellement arrivée, quand exactement ce contrat a-t-il pris effet, à quel moment cette transaction bancaire a-t-elle été exécutée? Donc, dans de telles situations courantes, nous voulons le TIMESTAMP WITH TIME ZONEtype.

Pour plus de discussion, voir ma réponse à la question similaire, devrais-je stocker des horodatages UTC ou des heures locales pour les équipes

Postgres

Notez que Postgres n'enregistre jamais spécifiquement les informations de fuseau horaire spécifiées lors de l'insertion d'un horodatage.

  • TIMESTAMP WITH TIME ZONE
    • Tout fuseau horaire ou décalage spécifié inclus avec les données d'entrée est utilisé pour ajuster la valeur à UTC et est stocké. Les informations de zone / décalage passées sont alors ignorées. Penser TIMESTAMP WITH TIME ZONEà TIMESTAMP WITH RESPECT FOR TIME ZONE.
    • Le 7 mars de cette année, en Inde, l'heure du jour sera réglée sur l'heure UTC de midi à midi en soustrayant cinq heures et demie: 6h30.
  • TIMESTAMP WITHOUT TIME ZONE
    • Tout fuseau horaire ou décalage spécifié inclus avec les données d'entrée est entièrement ignoré.
    • En Inde, une entrée du 7 mars à midi au 7 mars de cette année est enregistrée, le 7 mars de cette année à midi, sans ajustement.

Le standard SQL aborde à peine les problèmes de comportement et de types de données date-heure. La base de données varie donc beaucoup dans le traitement de la date et de l’heure.

Basil Bourque
la source
En outre, avec les quarts de travail dans les usines (ou les hôpitaux), les heures de travail des personnes travaillant dans le cimetière les jours de passage à l’heure DST seront enregistrées de manière incorrecte, sans indication de fuseau horaire.
Jasen
Je pense qu'il y a une faute de frappe dans le dernier exemple: "Une entrée du 7 mars à midi ... devrait être enregistrée comme 21:00
suit
11

J'aimerais ajouter un autre point de vue à cela, qui va à l'encontre d'une grande partie de ce qui a été écrit dans les autres réponses. À mon avis, timestamp with time zonea très peu de cas d'utilisation valables, et timestamp without time zonedevrait généralement être préféré.

Tout d’abord, vous devez comprendre le modèle "UTC partout", qui est généralement recommandé pour toutes les applications qui n’exigent pas d’exigences particulières. Cela signifie simplement que votre application doit représenter tous ses horodatages en UTC, partout et tout le temps. Bien sûr, vous allez montrer la date / heure locale aux utilisateurs, mais l’idée est de les convertir au bord de votre programme, lors du rendu de la vue. C’est le bon endroit pour combiner l’horodatage UTC (que vous avez peut-être chargé depuis une base de données) et le fuseau horaire de l’utilisateur (qui peut provenir du navigateur) dans un horodatage local.

Si vous suivez ce modèle, alors timestamp with time zoneest un anti-modèle. Tout ce type fait que PostgreSQL ™ effectue des conversions de fuseau horaire lors de la lecture et de l'écriture d'horodatages, en fonction de votre TimeZonevariable de session PostgreSQL . Au lieu de traiter les fuseaux horaires aux limites de votre application, vous les avez introduits dans son cœur, dans la communication même avec votre base de données. Vous devez veiller à toujours avoir TimeZonecorrectement configuré PostgreSQL à tout moment, en ajoutant un autre point de défaillance et de confusion inutile.

Et pour quoi? Si vous suivez le modèle UTC partout, votre application n’a de toute façon que des horodatages UTC; alors pourquoi demander à votre base de données d’effectuer des conversions de fuseaux horaires sur celles-ci? Vous pouvez simplement les stocker dans une timestamp without time zonecolonne et les traiter comme si c'était toujours UTC. Pas de conversions, pas de fuseaux horaires, pas de complications.

Shay Rojansky
la source
2
Je pense que les partisans de timestamptz soutiennent également le modèle "UTC partout". C'est juste que la règle est simplement appliquée au niveau de la base de données au lieu de compter uniquement sur les développeurs d'applications / API pour l'appliquer? Si vous pouvez appliquer cette pratique, pourquoi pas? En outre, vous pouvez simplement imposer à toutes les connexions postgres de définir leur fuseau horaire sur UTC. Même s'ils ne le font pas, le format ISO contiendra le décalage tz. Donc, n’est-ce pas la même chose que le UTC partout mais imposé?
iamnat
3
Premièrement, si votre TimeZone PostgreSQL est défini sur autre chose que UTC et que vous utilisez timestamptz, votre programme lit des horodatages autres que UTC. Ce n'est tout simplement pas le motif "UTC partout" et, selon la langue de votre client, peut entraîner ou non de nombreuses complications. Soit vous êtes partout dans le monde, soit vous utilisez des horodatages locaux ....
Shay Rojansky
Deuxièmement, encore une fois, si vous êtes UTC partout dans votre application, il n’ya tout simplement pas de décalage tz à envoyer au format ISO pour vos horodatages. Les spécificités vont varier d'une langue à l'autre, mais vous devriez idéalement utiliser un type de client incapable de représenter autre chose qu'un horodatage UTC (par exemple, Instancedans NodaTime / JodaTime). Vous décrivez en gros une situation dans laquelle "UTC partout" est presque suivie, ou un peu suivie ...
Shay Rojansky
Une fois encore, il est très facile d’imaginer qu’une nouvelle instance PostgreSQL soit configurée sur un serveur, conservant accidentellement le fuseau horaire de la machine locale configuré par défaut. Les applications lisent à partir de ce serveur et obtiennent des horodatages locaux dans un fuseau horaire totalement arbitraire (dans lequel le serveur se trouve). Pourquoi voudrions-nous cette complication supplémentaire?
Shay Rojansky
1
Ce pourrait être le cas, mais son utilisation aurait encore moins de sens timestamptz. L’intérêt de ce type est d’effectuer des conversions de fuseau horaire en tant que valeurs lues et écrites dans PostgreSQL (en interne dans la base de données, l’horodatage est toujours enregistré au format UTC). Le fait de toujours définir le fuseau horaire de la session sur UTC désactive efficacement ces conversions, alors pourquoi l'utiliser timestamptz? En d'autres termes, si les valeurs de la base de données sont UTC et que les valeurs entrant et sortant de la base de données sont toujours UTC, pourquoi avoir la présence d'un fuseau horaire dans votre base de données?
Shay Rojansky le
2

L’ datehorodatage n’inclut pas non plus les informations de fuseau horaire, mais beaucoup de gens l’utilisent.

Bien sûr, cela en soi n'est pas une réponse.

Il est valide d'utiliser timestampet datepour tous les horodatages et dates qui sont toujours dans le même fuseau horaire ou qui sont stockés par rapport à un fuseau horaire connu.

Si le fuseau horaire est toujours identique ou implicite, il est plus contraignant de le stocker que de ne pas le stocker (informations redondantes).

Les horodatages peuvent également être utilisés pour stocker des informations techniques telles que celles utilisées dans les journaux d'application ou pour les mesures de performances. Dans ce cas, le fuseau horaire peut également être sans importance.


Inversement, si vous concevez ou travaillez sur un système distribué ou dans un système dans lequel des parties du système seront réparties sur des fuseaux horaires différents, cela peut être considéré comme un anti-motif à ne pas utiliser timestamp with timezone, même si certains systèmes peuvent être conçus pour s'exécuter dans un fuseau horaire, p.ex. UTC. Dans ce cas, la logique du fuseau horaire peut être poussée dans la couche application - mais je considérerais cela comme un anti-motif, oui.

Colin 't Hart
la source
Je comprends que dans certains cas, l’utilisation ne me fait pas mal timestamp without timezone, mais est-ce que cela m’achète quelque chose? Sinon, pourquoi devrais-je m'embêter si le timestamp with timezone datatype est toujours égal ou plus approprié?
Marcus Junius Brutus
Ne pas stocker d'informations redondantes serait mon principal argument. Je suppose que l'arithmétique des dates timestamp without timezoneserait plus rapide aussi, mais ce n'est probablement important que si vous traitez des milliards de lignes ...
Colin 't Hart
1
@ Colin'tHart timestampet timestamptzsont tous deux stockés de la même manière. Aucune information de fuseau horaire n'est stockée dans a timestamptz, mais elle est convertie au format UTC pour le stockage. Je dirais, utilisez toujours timestamptzlorsque les horodatages en question indiquent l'heure absolue . C'est tout ce que timestamptzsignifie. J'ai écrit à ce sujet ici .
Fphilipe
2

Il peut sembler temporaire de stocker et de traiter les dates / heures à l’heure locale si votre application est limitée à un seul fuseau horaire, mais j’estime qu’il s’agit d’une erreur.

Lorsque vous passez de l'heure d'été à l'heure normale, l'heure locale est répétée (en supposant que la différence est d'une heure). Là où j'habite, cela se produit généralement autour de 2 heures du matin, donc l'heure locale est 01:58, 01:59, 01:00 et ne avance qu'à 02:00 à la fin de l'heure.

Si vous essayez de classer les événements par heure en utilisant l'heure locale, cela signifie que les événements de deux heures distinctes sont mélangés et n'apparaissent pas dans l'ordre dans lequel ils se sont réellement déroulés.

En comparaison, UTC n'a pas ce problème et commande proprement. Ainsi, même lorsque vous travaillez avec un seul fuseau horaire, vous souhaitez que la base de données stocke et traite les heures au format UTC et les convertisse en / à partir de l'heure locale à des fins de saisie / affichage. C'est le comportement de TIMESTAMP WITH TIME ZONE.

Steve Fosdick
la source