web-dev-qa-db-fra.com

Python: déterminer le fuseau horaire local

Je souhaite comparer les horodatages UTC d'un fichier journal avec les horodatages locaux. Lors de la création de l'objet datetime local, j'utilise quelque chose comme:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0, 
                                 tzinfo=pytz.timezone('Israel'))

Je veux trouver un outil automatique qui remplacerait la tzinfo=pytz.timezone('Israel') par le fuseau horaire local actuel.

Des idées?

45
Adam Matan

Essayez dateutil , qui a le type tzlocal qui fait ce dont vous avez besoin.

29
Steven

Dans Python 3.x, le fuseau horaire local peut être défini comme suit:

import datetime
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo

C'est une utilisation délicate de datetime's code .

43
vbem

comparer les horodatages UTC d'un fichier journal avec les horodatages locaux.

Il est difficile de trouver le nom Olson TZ pour un fuseau horaire local de manière portable. Heureusement, vous n'en avez pas besoin pour effectuer la comparaison.

tzlocal module retourne un fuseau horaire pytz correspondant au fuseau horaire local:

from datetime import datetime

import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

tz = get_localzone()
local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc) #NOTE: utc.normalize() is unnecessary here

Contrairement aux autres solutions présentées jusqu'à présent, le code ci-dessus évite les problèmes suivants:

  • l’heure locale peut être ambiguë c’est-à-dire qu’une comparaison précise peut être impossible pour certaines heures locales
  • utc offset peut être différent pour le même nom de fuseau horaire local que pour les dates antérieures. Certaines bibliothèques qui prennent en charge les objets datetime compatibles avec les fuseaux horaires (par exemple, dateutil) ne parviennent pas à en tenir compte.

Remarque: pour obtenir un objet datetime compatible avec un fuseau horaire à partir d’un objet datetime naïf, vous devez utiliser*:

local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)

au lieu de:

#XXX fails for some timezones
local_dt = datetime(2010, 4, 27, 12, 0, 0, 0, tzinfo=tz)

*is_dst=None force une exception si l'heure locale donnée est ambiguë ou inexistante.

Si vous êtes certain que tous les horodatages locaux utilisent le même décalage (actuel) utc pour le fuseau horaire local, vous pouvez effectuer la comparaison en utilisant uniquement stdlib:

# convert a naive datetime object that represents time in local timezone to Epoch time
timestamp1 = (datetime(2010, 4, 27, 12, 0, 0, 0) - datetime.fromtimestamp(0)).total_seconds()

# convert a naive datetime object that represents time in UTC to Epoch time
timestamp2 = (datetime(2010, 4, 27, 9, 0) - datetime.utcfromtimestamp(0)).total_seconds()

timestamp1 et timestamp2 peuvent être comparés directement.

Remarque: 

  • La formule timestamp1 ne fonctionne que si l'offset UTC à Epoch (datetime.fromtimestamp(0)) est identique à maintenant
  • fromtimestamp() crée un objet date/heure naïf dans le fuseau horaire local actuel
  • utcfromtimestamp() crée un objet date/heure naïf au format UTC.
26
jfs

Je me demandais la même chose et j'ai trouvé la réponse en 1:

Jetez un coup d’œil à la section 8.1.7: le format "% z" (en minuscule, la majuscule Z renvoie également le fuseau horaire, mais pas au format à 4 chiffres, mais sous la forme d’abréviations de fuseau horaire, comme dans [3]) of strftime renvoie le formulaire "+/- 4DIGIT" standard dans les en-têtes de courrier électronique (voir la section 3.3 de la RFC 2822, voir [2], qui rend obsolètes les autres moyens de spécifier le fuseau horaire des en-têtes de courrier électronique).

Donc, si vous voulez que votre fuseau horaire soit dans ce format, utilisez: 

time.strftime("%z")

[1] http://docs.python.org/2/library/datetime.html

[2] http://tools.ietf.org/html/rfc2822#section-3.3

[3] Abréviations de fuseau horaire: http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations , uniquement à titre de référence.

11
David L

Commencez par obtenir les modules pytz et tzlocal

pip install pytz tzlocal

puis

from tzlocal import get_localzone
local = get_localzone()

alors vous pouvez faire des choses comme

from datetime import datetime
print(datetime.now(local))
5
aminalid

Basé sur la réponse de J. F. Sebastian , vous pouvez le faire avec la bibliothèque standard:

import time, datetime
local_timezone = datetime.timezone(datetime.timedelta(seconds=-time.timezone))

Testé en 3.4, devrait fonctionner sur 3.4+

3
Gilly

Voici une version légèrement plus concise de la solution de @ vbem:

from datetime import datetime as dt

dt.utcnow().astimezone().tzinfo

La seule différence importante est que j'ai remplacé datetime.datetime.now(datetime.timezone.utc) par datetime.datetime.utcnow(). Par souci de brièveté, j'ai aussi aliasé datetime.datetime en tant que dt.

Pour mes besoins, je veux le décalage UTC en secondes. Voici à quoi ça ressemble:

dt.utcnow().astimezone().utcoffset().total_seconds()
3
David Marx

Voici un moyen d'obtenir le fuseau horaire local en utilisant uniquement la bibliothèque standard (ne fonctionne que dans un environnement * nix):

>>> '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
'Australia/Sydney'

Vous pouvez l'utiliser pour créer un fuseau horaire pytz:

>>> import pytz
>>> my_tz_name = '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
>>> my_tz = pytz.timezone(my_tz_name)
>>> my_tz
<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>

... que vous pouvez ensuite appliquer à une datetime:

>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059)

>>> now.replace(tzinfo=my_tz)
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059, tzinfo=<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>)
3
amorphic

Sur la base de la réponse ci-dessus de Thoku, voici une réponse qui résout le fuseau horaire à la demi-heure la plus proche (ce qui est pertinent pour certains fuseaux horaires, par exemple celui de l'Australie méridionale):

from datetime import datetime
round((round((datetime.now()-datetime.utcnow()).total_seconds())/1800)/2)
2
user2380550

Eviter le module non standard (semble être une méthode manquante du module datetime):

from datetime import datetime
utcOffset_min = int(round((datetime.now() - datetime.utcnow()).total_seconds())) / 60   # round for taking time twice
utcOffset_h = utcOffset_min / 60
assert(utcOffset_min == utcOffset_h * 60)   # we do not handle 1/2 h timezone offsets

print 'Local time offset is %i h to UTC.' % (utcOffset_h)
2
thoku

Pour des raisons simples, vous pouvez utiliser l’implémentation tzinfo suivante, qui interroge le système d’exploitation sur les décalages de fuseau horaire:

import datetime
import time

class LocalTZ(datetime.tzinfo):
    _unixEpochOrdinal = datetime.datetime.utcfromtimestamp(0).toordinal()

    def dst(self, dt):
        return datetime.timedelta(0)

    def utcoffset(self, dt):
        t = (dt.toordinal() - self._unixEpochOrdinal)*86400 + dt.hour*3600 + dt.minute*60 + dt.second + time.timezone
        utc = datetime.datetime(*time.gmtime(t)[:6])
        local = datetime.datetime(*time.localtime(t)[:6])
        return local - utc


print datetime.datetime.now(LocalTZ())
print datetime.datetime(2010, 4, 27, 12, 0, 0, tzinfo=LocalTZ())

# If you're in the EU, the following datetimes are right on the DST change.
print datetime.datetime(2013, 3, 31, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 59, 59, tzinfo=LocalTZ())

# The following datetime is invalid, as the clock moves directly from
# 01:59:59 standard time to 03:00:00 daylight savings time.
print datetime.datetime(2013, 3, 31, 2, 0, 0, tzinfo=LocalTZ())

print datetime.datetime(2013, 10, 27, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 59, 59, tzinfo=LocalTZ())

# The following datetime is ambigous, as 02:00 can be either DST or standard
# time. (It is interpreted as standard time.)
print datetime.datetime(2013, 10, 27, 2, 0, 0, tzinfo=LocalTZ())
1
Søren Løvborg

Tout d'abord, notez que la question présente une initialisation incorrecte d'un objet datetime conscient:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0,
...                                  tzinfo=pytz.timezone('Israel'))

crée une instance invalide. On peut voir le problème en calculant le décalage UTC de l'objet résultant:

>>> print(local_time.utcoffset())
2:21:00

(Notez le résultat qui est une fraction d'heure impaire.)

Pour initialiser correctement une date/heure conscient en utilisant pytz, vous devez utiliser la méthode localize() comme suit:

>>> local_time=pytz.timezone('Israel').localize(datetime.datetime(2010, 4, 27, 12))
>>> print(local_time.utcoffset())
3:00:00

Maintenant, si vous avez besoin d’un fuseau horaire pytz local en tant que nouveau tzinfo, vous devez utiliser le paquet tzlocal comme l’ont déjà expliqué d’autres appelez la méthode astimezone() sans argument pour convertir une instance datetime au courant en votre fuseau horaire local:

>>> local_time.astimezone().strftime('%Y-%m-%d %H:%M %Z %z')
'2010-04-27 05:00 EDT -0400'
0

Vous pouvez être heureux avec pendule

>>> pendulum.datetime(2015, 2, 5, tz='local').timezone.name
'Israel'

Pendulum a une API bien conçue pour manipuler les dates. Tout est conscient de la TZ.

0
Étienne Bersac
now_dt = datetime.datetime.now()
utc_now = datetime.datetime.utcnow()
now_ts, utc_ts = map(time.mktime, map(datetime.datetime.timetuple, (now_dt, utc_now)))
offset = int((now_ts - utc_ts) / 3600)

j'espère que ceci vous aidera.

0
宝城 p