web-dev-qa-db-fra.com

Python: Comment obtenir une valeur de datetime.today () "consciente du fuseau horaire"?

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.

226
mindthief

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:

290
AndiDog

Obtenir l'heure actuelle, dans un fuseau horaire spécifique:

import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific'))
80
philfreo

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 .

37
Flimm

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

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é .

16
jfs

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() )  
11
Dariusz Walczak

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
8
laffuste

pytz est une bibliothèque Python qui permet des calculs de fuseau horaire multi-plateformes précis avec Python version 2.3 ou supérieure.

Avec stdlib, ce n'est pas possible. 

Voir une question similaire sur SO .

6
user225312

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

5
jcazor

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())
4
G. Führ

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.

1
Antony Hatchkins

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
1
Mihai Capotă

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"))
0
jigar vagadiya

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.

0
tmck-code

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() 
0
Anupama V Iyengar