J'essaie de soustraire une valeur de date de la valeur de datetime.today()
pour calculer le temps écoulé. Mais il se plaint:
TypeError: can't subtract offset-naive and offset-aware datetimes
La valeur datetime.today()
ne semble pas être "sensible au fuseau horaire", alors que mon autre valeur de date est. Comment puis-je obtenir une valeur de datetime.today()
qui prend en compte le fuseau horaire? À l’heure actuelle, cela me donne l’heure locale, qui se trouve être PST, c’est-à-dire UTC-8h. Dans le pire des cas, y a-t-il moyen de saisir manuellement une valeur de fuseau horaire dans l'objet datetime
renvoyé par datetime.today()
et de le définir sur UTC-8? Bien entendu, la solution idéale serait de connaître automatiquement le fuseau horaire.
Dans la bibliothèque standard, il n'existe pas de moyen multiplateforme pour créer des fuseaux horaires conscients sans créer votre propre classe de fuseau horaire.
Sur Windows, il y a win32timezone.utcnow()
, mais cela fait partie de pywin32. Je suggérerais plutôt d’utiliser la bibliothèque pytz , qui dispose d’une base de données constamment mise à jour de la plupart des fuseaux horaires.
Travailler avec des fuseaux horaires locaux peut être très délicat (voir les liens "Autres lectures" ci-dessous). Vous pouvez donc préférer utiliser l'UTC dans votre application, en particulier pour les opérations arithmétiques telles que le calcul de la différence entre deux points horaires.
Vous pouvez obtenir la date/heure actuelle comme suit:
import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc)
Notez que datetime.today()
et datetime.now()
renvoient l’heure local, et non l’heure UTC. L’application de .replace(tzinfo=pytz.utc)
ne serait donc pas correcte.
Une autre façon agréable de le faire est:
datetime.now(pytz.utc)
qui est un peu plus court et fait la même chose.
Lectures supplémentaires/regarder pourquoi préférer UTC dans de nombreux cas:
Obtenir l'heure actuelle, dans un fuseau horaire spécifique:
import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific'))
Dans Python 3, la bibliothèque standard facilite la spécification de l'heure UTC comme fuseau horaire:
>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2016, 8, 26, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc)
Si vous voulez une solution qui utilise uniquement la bibliothèque standard et qui fonctionne à la fois avec Python 2 et Python 3, voir Réponse de J. F. Sebastien .
Voici une solution stdlib qui fonctionne à la fois sur Python 2 et 3:
from datetime import datetime
now = datetime.now(utc) # timezone-aware datetime.utcnow()
today = datetime(now.year, now.month, now.day, tzinfo=utc) # midnight
où today
est une instance de date/heure au courant représentant le début de la journée (minuit) en UTC et utc
est un objet tzinfo ( exemple tiré de la documentation ):
from datetime import tzinfo, timedelta
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()
En relation: comparaison des performances de plusieurs façons d’obtenir minuit (début de la journée) pour une heure UTC donnée .
Remarque: il est plus complexe de obtenir minuit pour un fuseau horaire avec un décalage utc non fixé .
Une autre méthode pour construire un objet datetime prenant en charge le fuseau horaire représentant l’heure actuelle:
import datetime
import pytz
pytz.utc.localize( datetime.datetime.utcnow() )
Si vous utilisez Django, vous pouvez définir des dates non compatibles avec tz (uniquement utc).
Commentaire la ligne suivante dans settings.py:
USE_TZ = True
Voici un moyen de le générer avec stdlib:
import time
from datetime import datetime
FORMAT='%Y-%m-%dT%H:%M:%S%z'
date=datetime.strptime(time.strftime(FORMAT, time.localtime()),FORMAT)
date stockera la date locale et le décalage par rapport à UTC, et non la date au fuseau horaire UTC. Vous pouvez donc utiliser cette solution si vous devez identifier le fuseau horaire dans lequel la date est générée à. Dans cet exemple et dans mon fuseau horaire local:
date
datetime.datetime(2017, 8, 1, 12, 15, 44, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))
date.tzname()
'UTC+02:00'
La clé ajoute la directive %z
à la représentation FORMAT pour indiquer le décalage UTC de la structure de temps générée. D'autres formats de représentation peuvent être consultés dans le module datetime docs
Si vous avez besoin de la date au fuseau horaire UTC, vous pouvez remplacer time.localtime () avec time.gmtime ()
date=datetime.strptime(time.strftime(FORMAT, time.gmtime()),FORMAT)
date
datetime.datetime(2017, 8, 1, 10, 23, 51, tzinfo=datetime.timezone.utc)
date.tzname()
'UTC'
Modifier
Ceci ne fonctionne que sur python3. La directive z n'est pas disponible sur python 2 _strptime.py code
Pourquoi ne pas utiliser dateutil comme décrit ici: http://joelinoff.com/blog/?p=802
from dateutil.tz import tzlocal
# Get the current date/time with the timezone.
now = datetime.datetime.now(tzlocal())
Obtenir une date correspondant à un fuseau horaire dans utc
fuseau horaire suffit pour que la soustraction de date fonctionne.
Mais si vous voulez une date tenant compte du fuseau horaire dans votre fuseau horaire actuel, tzlocal
est le chemin à parcourir:
from tzlocal import get_localzone # pip install tzlocal
from datetime import datetime
datetime.now(get_localzone())
PS dateutil
a une fonction similaire (dateutil.tz.tzlocal
). Malgré le fait de partager le nom, il a une base de code complètement différente, qui comme notée par J.F. Sebastian peut donner des résultats erronés.
Vous pouvez créer une timezone
locale en utilisant datetime
en analysant le résultat d'un appel time.strftime
qui utilise la directive %z
(introduite dans Python 3.3), telle que indiquée par jcazor . Vous pouvez utiliser cette timezone
pour créer une instance datetime
au courant avec une ligne:
import time
from datetime import datetime
aware_local_now = datetime.now(
tz=datetime.strptime(time.strftime("%z", time.localtime()), "%z").tzinfo)
print(aware_local_now)
2018-03-01 13:41:26.753644-08:00
Si vous obtenez l'heure et la date actuelles en python, puis importez la date et l'heure, le paquet pytz en python après avoir obtenu la date et l'heure actuelles, comme si ..
from datetime import datetime
import pytz
import time
str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t"))
J'ajoute cette réponse en tant que personne travaillant fréquemment avec des fuseaux horaires non UTC.
Le seul fuseau horaire qui a sa propre méthode est timezone.utc
, mais vous pouvez le caler avec n'importe quel décalage UTC si vous devez utiliser timedelta
& timezone
et le forcer avec .replace
.
In [1]: from datetime import datetime, timezone, timedelta
In [2]: def force_timezone(dt, utc_offset=0):
...: return dt.replace(tzinfo=timezone(timedelta(hours=utc_offset)))
...:
In [3]: dt = datetime(2011,8,15,8,15,12,0)
In [4]: str(dt)
Out[4]: '2011-08-15 08:15:12'
In [5]: str(force_timezone(dt, -8))
Out[5]: '2011-08-15 08:15:12-08:00'
Utiliser timezone(timedelta(hours=n))
comme fuseau horaire est la solution miracle, et il propose de nombreuses autres applications utiles.
Utilisez le fuseau horaire comme indiqué ci-dessous pour connaître la date et l'heure, le temps par défaut étant UTC:
from Django.utils import timezone
today = timezone.now()