Question

Le mieux que je peux trouver pour est maintenant cette monstruosité:

>>> datetime.utcnow() \
...   .replace(tzinfo=pytz.UTC) \
...   .astimezone(pytz.timezone("Australia/Melbourne")) \
...   .replace(hour=0,minute=0,second=0,microsecond=0) \
...   .astimezone(pytz.UTC) \
...   .replace(tzinfo=None)
datetime.datetime(2008, 12, 16, 13, 0)

i.e.., En anglais, obtenir l'heure actuelle (UTC), le convertir en un autre fuseau horaire, régler l'heure à minuit, puis reconvertir en UTC.

Je ne suis pas seulement en utilisant maintenant () ou localtime () car cela utiliser le fuseau horaire du serveur, et non le fuseau horaire de l'utilisateur.

Je ne peux pas aider sentiment que je me manque quelque chose, des idées?

Était-ce utile?

La solution

Je pense que vous pouvez raser quelques appels de méthode si vous le faites comme ceci:

>>> from datetime import datetime
>>> datetime.now(pytz.timezone("Australia/Melbourne")) \
            .replace(hour=0, minute=0, second=0, microsecond=0) \
            .astimezone(pytz.utc)

Mais ... il y a un problème plus grand que l'esthétique de votre code. Il donnera le mauvais résultat le jour du commutateur ou de l'heure d'été

La raison est que ni les constructeurs datetime ni replace() prennent en compte l'heure d'été change.

Par exemple:

>>> now = datetime(2012, 4, 1, 5, 0, 0, 0, tzinfo=pytz.timezone("Australia/Melbourne"))
>>> print now
2012-04-01 05:00:00+10:00
>>> print now.replace(hour=0)
2012-04-01 00:00:00+10:00 # wrong! midnight was at 2012-04-01 00:00:00+11:00
>>> print datetime(2012, 3, 1, 0, 0, 0, 0, tzinfo=tz)
2012-03-01 00:00:00+10:00 # wrong again!

Toutefois, la documentation pour les Etats tz.localize():

  

Cette méthode doit être utilisée pour construire LocalTimes, plutôt   que le passage d'un argument tzinfo à un constructeur dateheure.

Ainsi, votre problème est résolu comme ceci:

>>> import pytz
>>> from datetime import datetime, date, time

>>> tz = pytz.timezone("Australia/Melbourne")
>>> the_date = date(2012, 4, 1) # use date.today() here

>>> midnight_without_tzinfo = datetime.combine(the_date, time())
>>> print midnight_without_tzinfo
2012-04-01 00:00:00

>>> midnight_with_tzinfo = tz.localize(midnight_without_tzinfo)
>>> print midnight_with_tzinfo
2012-04-01 00:00:00+11:00

>>> print midnight_with_tzinfo.astimezone(pytz.utc)
2012-03-31 13:00:00+00:00

Aucune garantie pour les dates avant 1582, cependant.

Autres conseils

@ de réponse hop est faux le jour de transition de l'heure d'été (DST), par exemple, 1 avril 2012 . Pour résoudre ce problème tz.localize() pourrait être utilisé:

tz = pytz.timezone("Australia/Melbourne")
today = datetime.now(tz).date()
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
utc_dt = midnight.astimezone(pytz.utc)        

La même chose avec les commentaires:

#!/usr/bin/env python
from datetime import datetime, time
import pytz # pip instal pytz

tz = pytz.timezone("Australia/Melbourne") # choose timezone

# 1. get correct date for the midnight using given timezone.
today = datetime.now(tz).date()

# 2. get midnight in the correct timezone (taking into account DST)
#NOTE: tzinfo=None and tz.localize()
# assert that there is no dst transition at midnight (`is_dst=None`)
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)

# 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no 
#    DST transitions)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
print midnight.astimezone(pytz.utc).strftime(fmt)

Réglage de la variable d'environnement TZ modifie quelle date de fuseau horaire Python et les fonctions de temps avec les.

>>> time.gmtime()
(2008, 12, 17, 1, 16, 46, 2, 352, 0)
>>> time.localtime()
(2008, 12, 16, 20, 16, 47, 1, 351, 0)
>>> os.environ['TZ']='Australia/Melbourne'
>>> time.localtime()
(2008, 12, 17, 12, 16, 53, 2, 352, 1)

Chaque fois que la zone a un certain nombre, par exemple US / Central = -6. Ceci est défini comme le décalage des heures de UTC. Depuis 0000 est minuit, vous pouvez simplement utiliser ce décalage pour trouver le temps dans un fuseau horaire quand il est minuit UTC. Pour accéder à cela, je crois que vous pouvez utiliser

 time.timezone

Selon Python Docs, time.timezone donne en fait la valeur négative de ce nombre:

  
    

time.timezone

         
      

Le décalage du fuseau horaire local (non-DST), en quelques secondes à l'ouest de UTC (négatif dans la plupart de l'Europe occidentale, positif aux États-Unis, zéro au Royaume-Uni).

    
  

Donc, vous simplement utiliser ce numéro pour le temps en heures si elle est positive (à savoir, s'il est minuit à Chicago (qui a une valeur de fuseau horaire +6), alors il est 6000 = UTC 6 heures).

Si le nombre est négatif, il faut soustraire de 24. Par exemple, Berlin donnerait -1, donc 24 -. 1 => 2300 = 23:00

Ceci est plus simple avec dateutil.tz que pytz:

>>>import datetime
>>>import dateutil.tz
>>>midnight=(datetime.datetime
             .now(dateutil.tz.gettz('Australia/Melbourne'))
             .replace(hour=0, minute=0, second=0, microsecond=0)
             .astimezone(dateutil.tz.tzutc()))
>>>print(midnight)
2019-04-26 14:00:00+00:00

La documentation tzinfo recommande dateutil.tz depuis Python 3.6. Les objets tzinfo de dateutil.tz ont pas de problèmes avec des anomalies comme DST sans nécessiter la fonctionnalité de pytz localize. En utilisant l'exemple de user3850:

>>> now = (datetime.datetime(2012, 4, 1, 5,  
...         tzinfo = dateutil.tz.gettz('Australia/Melbourne'))) 
>>> print(now.replace(hour = 0).astimezone(dateutil.tz.tzutc()))
2012-03-31 13:00:00+00:00
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top