Discussion:
datetime : passer d'« offset-naive » à « offset-aware »
(trop ancien pour répondre)
Olivier Miakinen
2023-05-14 19:29:35 UTC
Permalink
Bonjour,

Je voudrais pouvoir comparer en python des dates de courriels, au format défini
par le RFC2822. Pour cela, j'utilise la fonction parsedate_to_datetime() qui est
définie dans le module email.utils :

from email.utils import parsedate_to_datetime
date = parsedate_to_datetime("Sat, 13 May 2023 12:00:00 +0200")


Tout fonctionne très bien, y compris lorsque le timezone est +0000. Mais lorsque
c'est -0000 le datetime correspondant se retrouve sans aucun tzinfo :

date1 = parsedate_to_datetime("Sat, 13 May 2023 12:00:00 +0000")
-> datetime.datetime(2023, 5, 13, 12, 0, tzinfo=datetime.timezone.utc)

date2 = parsedate_to_datetime("Sat, 13 May 2023 12:00:00 -0000")
-> datetime.datetime(2023, 5, 13, 12, 0)


Le problème est qu'alors python refuse de faire la différence entre ce datetime
sans tzinfo et ceux qui en ont un :

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


D'où ma question : comment détecter qu'un datetime n'a pas de tzinfo, et dans
ce cas seulement lui coller le tzinfo=datetime.timezone.utc ? Ou bien, autre
solution, est-ce que je peux remplacer parsedate_to_datetime() par une fonction
qui définirait bien le tzinfo dans tous les cas ?
--
Olivier Miakinen
Olivier Miakinen
2023-05-14 19:56:26 UTC
Permalink
Re-bonjour,
Post by Olivier Miakinen
Je voudrais pouvoir comparer en python des dates de courriels, au format défini
par le RFC2822. Pour cela, j'utilise la fonction parsedate_to_datetime() qui est
from email.utils import parsedate_to_datetime
date = parsedate_to_datetime("Sat, 13 May 2023 12:00:00 +0200")
[...] comment détecter qu'un datetime n'a pas de tzinfo, et dans
ce cas seulement lui coller le tzinfo=datetime.timezone.utc ? Ou bien, autre
solution, est-ce que je peux remplacer parsedate_to_datetime() par une fonction
qui définirait bien le tzinfo dans tous les cas ?
Bon, RTFM comme on dit, j'ai lu le manuel et j'arrive à ça :

===============================================================
from email.utils import parsedate_to_datetime
from datetime import datetime, timezone

def my_parsedate(rfc2822_date):
d = parsedate_to_datetime(rfc2822_date)
if (d.tzinfo is None) or (d.tzinfo.utcoffset(d) is None):
# d is a naive timedate, make it aware
d = datetime.combine(d.date(), d.time(), timezone.utc)
return d
===============================================================

Est-ce que ça vous semble correct ? Et si même ça l'est, y aurait-il mieux ?


Cordialement,
--
Olivier Miakinen
Stefan Ram
2023-05-14 20:10:12 UTC
Permalink
Post by Olivier Miakinen
Est-ce que ça vous semble correct ?
Et si même ça l'est, y aurait-il mieux ?
La documentation de "classe email.headerregistry.DateHeader"
contient (traduit) :

|datetime
|Si la valeur de l'en-tête peut être reconnue comme une date
|valide d'une forme ou d'une autre, cet attribut contiendra une
|instance de datetime représentant cette date. Si le fuseau horaire
|de la date d'entrée est spécifié comme étant -0000 (ce qui indique
|qu'elle est en UTC mais ne contient aucune information sur le
|fuseau horaire de la source), datetime sera une datetime naïve.
|Si un décalage de fuseau horaire spécifique est trouvé (y compris
|+0000), datetime contiendra une datetime consciente qui utilise
|datetime.timezone pour enregistrer le décalage de fuseau horaire.

(Un autre paragraphe similaire se trouve encore dans la documentation
de "email.utils.parsedate_to_datetime" et des fonctions suivantes.)

J'en déduis que "-0000" signifie que la date ne tient pas
compte du fuseau horaire, tandis que "+0000" est une date qui
tient compte du fuseau horaire, et que ces deux éléments ne
peuvent pas être soustraits.
Olivier Miakinen
2023-05-14 20:20:07 UTC
Permalink
Post by Stefan Ram
La documentation de "classe email.headerregistry.DateHeader"
|datetime
|Si la valeur de l'en-tête peut être reconnue comme une date
|valide d'une forme ou d'une autre, cet attribut contiendra une
|instance de datetime représentant cette date. Si le fuseau horaire
|de la date d'entrée est spécifié comme étant -0000 (ce qui indique
|qu'elle est en UTC mais ne contient aucune information sur le
|fuseau horaire de la source), datetime sera une datetime naïve.
|Si un décalage de fuseau horaire spécifique est trouvé (y compris
|+0000), datetime contiendra une datetime consciente qui utilise
|datetime.timezone pour enregistrer le décalage de fuseau horaire.
(Un autre paragraphe similaire se trouve encore dans la documentation
de "email.utils.parsedate_to_datetime" et des fonctions suivantes.)
J'en déduis que "-0000" signifie que la date ne tient pas
compte du fuseau horaire, tandis que "+0000" est une date qui
tient compte du fuseau horaire, et que ces deux éléments ne
peuvent pas être soustraits.
En effet, je viens tout juste de lire ceci dans le RFC 2822 :

[...] The form "+0000" SHOULD be used to indicate a time zone at
Universal Time. Though "-0000" also indicates Universal Time, it is
used to indicate that the time was generated on a system that may be
in a local time zone other than Universal Time and therefore
indicates that the date-time contains no information about the local
time zone.

Du coup, la plupart de mes correspondants étant en France, ce -0000 pourrait
tout aussi bien signifier +0000 que +0200.

Bah, dans ce cas ce sera tant pis si je ne peux pas comparer les dates avec
une absolue certitude, de toute façon ça dépend aussi de l'horloge sur la
machine de l'émetteur. L'essentiel est que mon programme ne plante pas.
--
Olivier Miakinen
Thierry Pinelli
2023-05-15 08:36:01 UTC
Permalink
devenu 5322
Olivier Miakinen
2023-05-15 13:33:28 UTC
Permalink
Post by Thierry Pinelli
devenu 5322
Tu as tout à fait raison. Cela dit, et je viens de le vérifier, il n'y a pas
eu de modification concernant le format de la date (et en particulier le
timezone), contrairement à ce qui s'est passé entre les RFC 822 et 2822.
--
Olivier Miakinen
pata...@gmail.com
2023-05-25 13:48:57 UTC
Permalink
Post by Olivier Miakinen
Post by Thierry Pinelli
devenu 5322
Tu as tout à fait raison. Cela dit, et je viens de le vérifier, il n'y a pas
eu de modification concernant le format de la date (et en particulier le
timezone), contrairement à ce qui s'est passé entre les RFC 822 et 2822.
--
Olivier Miakinen
très bonne doc sur la problématique posée :
https://www.docstring.fr/blog/la-gestion-des-dates-avec-python/
si ça peut aider...
Olivier Miakinen
2023-05-25 15:31:28 UTC
Permalink
Bonjour,
Post by ***@gmail.com
https://www.docstring.fr/blog/la-gestion-des-dates-avec-python/
si ça peut aider...
Ah oui, cette page semble très bien, mais c'est un peu difficile à lire avec
le texte en gris sur fond bleu foncé. Heureusement ça redevient lisible si on
désactive les CSS.

Je vais la lire dès que j'aurai 28 minutes devant moi... ;-)
--
Olivier Miakinen
Loading...