368 votes

On ne peut pas soustraire les dates qui ne tiennent pas compte du décalage et celles qui tiennent compte du décalage.

J'ai une conscience du fuseau horaire timestamptz dans PostgreSQL. Lorsque je tire des données de la table, je veux ensuite soustraire l'heure actuelle pour obtenir l'âge.

Le problème que j'ai est que les deux datetime.datetime.now() y datetime.datetime.utcnow() semblent renvoyer des timestamps sans fuseau horaire, ce qui entraîne cette erreur :

TypeError: can't subtract offset-naive and offset-aware datetimes 

Existe-t-il un moyen d'éviter cela (de préférence sans utiliser de module tiers) ?

EDIT : Merci pour les suggestions, cependant essayer d'ajuster le fuseau horaire semble me donner des erreurs donc je vais juste utiliser des timestamps sans fuseau horaire dans PG et toujours insérer en utilisant :

NOW() AT TIME ZONE 'UTC'

De cette façon, tous mes timestamps sont UTC par défaut (même si c'est plus ennuyeux de le faire).

374voto

phillc Points 2748

Avez-vous essayé de supprimer la sensibilisation au fuseau horaire ?

de http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

Il faudra peut-être aussi ajouter la conversion des fuseaux horaires.

edit : Veuillez tenir compte de l'ancienneté de cette réponse. Une réponse impliquant d'AJOUTER l'information sur le fuseau horaire au lieu de la supprimer dans python 3 est ci-dessous. https://stackoverflow.com/a/25662061/93380

36 votes

Cela semble être la seule façon de procéder. C'est assez nul que python ait un support si mauvais pour les fuseaux horaires qu'il ait besoin d'un module tiers pour travailler correctement avec les timestamps

35 votes

(Juste pour mémoire) En fait, ajouter des informations sur le fuseau horaire serait une meilleure idée : stackoverflow.com/a/4530166/548696

8 votes

Les objets datetime naïfs sont intrinsèquement ambigus et doivent donc être évités. Il est il est facile d'ajouter tzinfo à la place

331voto

J.F. Sebastian Points 102961

La solution correcte consiste à ajouter l'information sur le fuseau horaire, par exemple pour obtenir l'heure actuelle sous la forme d'un objet datetime conscient dans Python 3 :

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

Sur les anciennes versions de Python, vous pouviez définir le paramètre utc tzinfo vous-même (exemple tiré de la documentation sur les dates) :

from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)

class UTC(tzinfo):
  def utcoffset(self, dt):
    return ZERO
  def tzname(self, dt):
    return "UTC"
  def dst(self, dt):
    return ZERO

utc = UTC()

alors :

now = datetime.now(utc)

74voto

sage Points 555

Je sais que certaines personnes utilisent Django spécifiquement comme une interface pour abstraire ce type d'interaction avec la base de données. Django fournit des utilitaires qui peuvent être utilisés pour cela :

from django.utils import timezone
now_aware = timezone.now()

Vous devez mettre en place une infrastructure de base pour les paramètres de Django, même si vous n'utilisez que ce type d'interface (dans les paramètres, vous devez inclure les éléments suivants USE_TZ=True pour obtenir une date consciente).

En soi, c'est probablement loin d'être suffisant pour vous motiver à utiliser Django comme interface, mais il existe de nombreux autres avantages. D'un autre côté, si vous êtes tombé ici parce que vous avez malmené votre application Django (comme je l'ai fait), alors peut-être que ceci vous aidera...

41voto

ePi272314 Points 4098

Il s'agit d'une solution très simple et claire
Deux lignes de code

# First we obtain de timezone info o some datatime variable    

tz_info = your_timezone_aware_variable.tzinfo

# Now we can subtract two variables using the same time zone info
# For instance
# Lets obtain the Now() datetime but for the tz_info we got before

diff = datetime.datetime.now(tz_info)-your_timezone_aware_variable

Conclusion : Vous devez gérer vos variables de temps avec les mêmes informations de temps.

13voto

JeffC Points 431

Vous n'avez besoin de rien en dehors des librairies standard.

datetime.datetime.now().astimezone()

Si vous remplacez simplement le fuseau horaire, l'heure ne sera pas ajustée. Si votre système est déjà en UTC, .replace(tz='UTC') est parfait.

>>> x=datetime.datetime.now()
datetime.datetime(2020, 11, 16, 7, 57, 5, 364576)

>>> print(x)
2020-11-16 07:57:05.364576

>>> print(x.astimezone()) 
2020-11-16 07:57:05.364576-07:00

>>> print(x.replace(tzinfo=datetime.timezone.utc)) # wrong
2020-11-16 07:57:05.364576+00:00

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X