Ce que je dois faire
J'ai un objet datetime non compatible avec le fuseau horaire, auquel je dois ajouter un fuseau horaire afin de pouvoir le comparer avec d'autres objets datetime sensibles au fuseau horaire. Je ne veux pas convertir l'intégralité de mon application en fuseau horaire sans être au courant de ce cas hérité.
Ce que j'ai essayé
Tout d'abord, pour illustrer le problème:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
J'ai d'abord essayé l'astimezone:
>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>
Il n'est pas très surprenant que cela ait échoué, car il essaie en fait de faire une conversion. Remplacer semblait être un meilleur choix (selon Python: comment obtenir une valeur de datetime.today () qui est "sensible au fuseau horaire"? ):
>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>>
Mais comme vous pouvez le voir, replace semble définir le tzinfo, mais pas rendre l'objet conscient. Je me prépare à retravailler la chaîne d'entrée pour avoir un fuseau horaire avant de l'analyser (j'utilise dateutil pour l'analyse, si cela importe), mais cela semble incroyablement délicat.
De plus, j'ai essayé cela à la fois en python 2.6 et en python 2.7, avec les mêmes résultats.
Le contexte
J'écris un analyseur pour certains fichiers de données. Il y a un ancien format que je dois prendre en charge où la chaîne de date n'a pas d'indicateur de fuseau horaire. J'ai déjà corrigé la source de données, mais je dois toujours prendre en charge le format de données hérité. Une conversion unique des données héritées n'est pas une option pour diverses raisons commerciales BS. Bien qu'en général, je n'aime pas l'idée de coder en dur un fuseau horaire par défaut, dans ce cas, cela semble être la meilleure option. Je sais avec une confiance raisonnable que toutes les anciennes données en question sont en UTC, donc je suis prêt à accepter le risque de ne pas y parvenir dans ce cas.
unaware.replace()
retourneraitNone
s'il modifiait l'unaware
objet en place. Le REPL montre que.replace()
renvoie un nouveldatetime
objet ici.import datetime; datetime.datetime.now(datetime.timezone.utc)
tz
argument nommé pour être plus lisible:datetime.datetime.now(tz=datetime.timezone.utc)
Réponses:
En général, pour rendre un fuseau horaire naïf sensible au fuseau horaire, utilisez la méthode localize :
Pour le fuseau horaire UTC, il n'est pas vraiment nécessaire d'utiliser
localize
car il n'y a pas de calcul d'heure d'été pour gérer:travaux. (
.replace
renvoie un nouveau datetime; il ne modifie pasunaware
.)la source
aware = datetime(..., tz)
utilisez.localize()
plutôt.tz.localize(..., is_dst=None)
affirme que ce n'est pas le cas.Tous ces exemples utilisent un module externe, mais vous pouvez obtenir le même résultat en utilisant uniquement le module datetime, comme également présenté dans cette réponse SO :
Moins de dépendances et pas de problèmes pytz.
REMARQUE: Si vous souhaitez l'utiliser avec python3 et python2, vous pouvez également l'utiliser pour l'importation de fuseau horaire (codé en dur pour UTC):
la source
pytz
problèmes, je suis content d'avoir fait défiler un peu! Je ne voulais pas aborder avecpytz
sur mes serveurs distants en effet :)from datetime import timezone
fonctionne dans py3 mais pas py2.7.dt.replace(tzinfo=timezone.utc)
renvoie une nouvelle date / heure, elle ne se modifie pasdt
sur place. (Je vais modifier pour montrer cela).tz = pytz.timezone('America/Chicago')
J'ai utilisé de dt_aware à dt_unaware
et dt_unware à dt_aware
mais répondre avant est aussi une bonne solution.
la source
localtz.localize(dt_unware, is_dst=None)
pour déclencher une exception s'ildt_unware
représente une heure locale inexistante ou ambiguë (remarque: il n'y avait aucun problème de ce genre dans la révision précédente de votre réponse oùlocaltz
était UTC car UTC n'a pas de transition DSTJ'utilise cette déclaration dans Django pour convertir une heure inconnue en une heure consciente:
la source
Je suis d'accord avec les réponses précédentes, et ça va si vous êtes d'accord pour commencer en UTC. Mais je pense que c'est aussi un scénario courant pour les gens de travailler avec une valeur consciente de tz qui a un datetime qui a un fuseau horaire local non UTC.
Si vous deviez simplement vous rendre par son nom, on en déduirait probablement que replace () sera applicable et produira le bon objet sensible à l'heure. Ce n'est pas le cas.
le remplacement (tzinfo = ...) semble être aléatoire dans son comportement . C'est donc inutile. Ne l'utilisez pas!
localiser est la fonction correcte à utiliser. Exemple:
Ou un exemple plus complet:
me donne une valeur datetime sensible au fuseau horaire de l'heure locale actuelle:
la source
replace(tzinfo=...)
sur un fuseau horaire autre que UTC va salir votre datetime. J'ai eu-07:53
au lieu de-08:00
par exemple. Voir stackoverflow.com/a/13994611/1224827replace(tzinfo=...)
un comportement inattendu?Utilisez
dateutil.tz.tzlocal()
pour obtenir le fuseau horaire dans votre utilisation dedatetime.datetime.now()
etdatetime.datetime.astimezone()
:Notez que
datetime.astimezone
cela convertira d'abord votredatetime
objet en UTC puis dans le fuseau horaire, ce qui revient à appelerdatetime.replace
avec les informations de fuseau horaire d'origineNone
.la source
.replace(tzinfo=dateutil.tz.UTC)
.replace(tzinfo=datetime.timezone.utc)
Cela codifie les réponses de @ Sérgio et @ unutbu . Il "fonctionnera simplement" avec un
pytz.timezone
objet ou une chaîne de fuseau horaire IANA .Cela semble être ce que
datetime.localize()
(ou.inform()
ou.awarify()
) devrait faire, accepter à la fois les chaînes et les objets de fuseau horaire pour l'argument tz et par défaut à UTC si aucun fuseau horaire n'est spécifié.la source
Python 3.9 ajoute le
zoneinfo
module donc maintenant seule la bibliothèque standard est nécessaire!Attachez un fuseau horaire:
Attachez le fuseau horaire local du système:
Par la suite, il est correctement converti en d'autres fuseaux horaires:
Liste Wikipedia des fuseaux horaires disponibles
Windows n'a pas de base de données de fuseau horaire système, donc ici un package supplémentaire est nécessaire:
Il existe un backport pour permettre une utilisation en Python 3.6 à 3.8 :
Alors:
la source
pip install tzdata
Dans le format de la réponse d'unutbu; J'ai créé un module utilitaire qui gère des choses comme ça, avec une syntaxe plus intuitive. Peut être installé avec pip.
la source
pour ceux qui veulent juste faire un datetime sensible au fuseau horaire
la source
assez nouveau pour Python et j'ai rencontré le même problème. Je trouve cette solution assez simple et pour moi ça marche très bien (Python 3.6):
la source
Changer de fuseau horaire
la source