web-dev-qa-db-fra.com

Convertir la chaîne de date / heure UTC en date / heure locale

Je n'ai jamais eu à convertir le temps vers et depuis UTC. Récemment, on a demandé à mon application de connaître le fuseau horaire et je me suis mise à tourner en rond. Beaucoup d'informations sur la conversion de l'heure locale en heure UTC, ce que j'ai trouvé assez élémentaire (peut-être que je ne le fais pas aussi bien), mais je ne trouve aucune information sur la conversion facile de l'heure UTC en fuseau horaire de l'utilisateur final.

En un mot, et Android app m'envoie (app-app app) des données et contient un horodatage. Pour stocker cet horodatage à l'heure utc que j'utilise:

datetime.utcfromtimestamp(timestamp)

Cela semble fonctionner. Lorsque mon application stocke les données, elles sont stockées 5 heures à l'avance (je suis EST -5).

Les données sont stockées sur BigTable de appengine et, une fois récupérées, elles se présentent sous la forme d'une chaîne, comme ceci:

"2011-01-21 02:37:21"

Comment convertir cette chaîne en DateTime dans le fuseau horaire correct de l'utilisateur?

En outre, quel est le stockage recommandé pour les informations de fuseau horaire des utilisateurs? (Comment stockez-vous généralement tz info, par exemple: "-5: 00" ou "EST", etc.?). Je suis sûr que la réponse à ma première question pourrait contenir un paramètre les réponses à la seconde.

184
MattoTodd

Si vous ne souhaitez pas fournir vos propres objets tzinfo, consultez la bibliothèque python-dateutil . Il fournit les implémentations tzinfo au-dessus d'une base de données zoneinfo (Olson) telles que vous pouvez faire référence aux règles de fuseau horaire par un nom quelque peu canonique.

from datetime import datetime
from dateutil import tz

# METHOD 1: Hardcode zones:
from_zone = tz.gettz('UTC')
to_zone = tz.gettz('America/New_York')

# METHOD 2: Auto-detect zones:
from_zone = tz.tzutc()
to_zone = tz.tzlocal()

# utc = datetime.utcnow()
utc = datetime.strptime('2011-01-21 02:37:21', '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in UTC time zone since 
# datetime objects are 'naive' by default
utc = utc.replace(tzinfo=from_zone)

# Convert time zone
central = utc.astimezone(to_zone)

Edit Exemple développé pour afficher l'utilisation de strptime

Edit 2 Correction de l'utilisation de l'API pour afficher une meilleure méthode de point d'entrée

Modifier 3 Méthodes de détection automatique incluses pour les fuseaux horaires (Yarin)

351
Joe Holloway

Voici une méthode résiliente qui ne dépend d'aucune bibliothèque externe:

from datetime import datetime
import time

def datetime_from_utc_to_local(utc_datetime):
    now_timestamp = time.time()
    offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
    return utc_datetime + offset

Cela évite les problèmes de synchronisation dans l'exemple de DelboyJay. Et les problèmes de moindre synchronisation dans l'amendement d'Erik van Oosten.

Comme note de bas de page intéressante, le décalage horaire calculé ci-dessus peut différer de l'expression apparemment équivalente suivante, probablement en raison de modifications de la règle de l'heure d'été:

offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!

Mise à jour: Cet extrait a la faiblesse d'utiliser le décalage UTC de l'heure actuelle, qui peut différer du décalage UTC de la date/heure d'entrée. Voir les commentaires sur cette réponse pour une autre solution.

Pour vous déplacer à différentes époques, saisissez l’époque du temps écoulé. Voici ce que je fais:

def utc2local (utc):
    Epoch = time.mktime(utc.timetuple())
    offset = datetime.fromtimestamp (Epoch) - datetime.utcfromtimestamp (Epoch)
    return utc + offset
37
David Foster

Voir la documentation datetime sur les objets tzinfo . Vous devez implémenter les fuseaux horaires que vous souhaitez gérer vous-même. Voici des exemples au bas de la documentation.

Voici un exemple simple:

from datetime import datetime,tzinfo,timedelta

class Zone(tzinfo):
    def __init__(self,offset,isdst,name):
        self.offset = offset
        self.isdst = isdst
        self.name = name
    def utcoffset(self, dt):
        return timedelta(hours=self.offset) + self.dst(dt)
    def dst(self, dt):
            return timedelta(hours=1) if self.isdst else timedelta(0)
    def tzname(self,dt):
         return self.name

GMT = Zone(0,False,'GMT')
EST = Zone(-5,False,'EST')

print datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(GMT).strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(EST).strftime('%m/%d/%Y %H:%M:%S %Z')

t = datetime.strptime('2011-01-21 02:37:21','%Y-%m-%d %H:%M:%S')
t = t.replace(tzinfo=GMT)
print t
print t.astimezone(EST)

Sortie

01/22/2011 21:52:09 
01/22/2011 21:52:09 GMT
01/22/2011 16:52:09 EST
2011-01-21 02:37:21+00:00
2011-01-20 21:37:21-05:00a
21
Mark Tolonen

Si vous souhaitez obtenir le résultat correct même pour l'heure correspondant à une heure locale ambiguë (par exemple, pendant une transition DST) et/ou si le décalage utc local est différent à des heures différentes dans votre fuseau horaire local, utilisez pytz fuseaux horaires:

#!/usr/bin/env python
from datetime import datetime
import pytz    # $ pip install pytz
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone() # get pytz tzinfo
utc_time = datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(local_timezone)
15
jfs

Si vous utilisez Django, vous pouvez utiliser la méthode timezone.localtime (voir https://docs.djangoproject.com/en/dev/topics/i18n/timezones/ ).

from Django.utils import timezone
date 
# datetime.datetime(2014, 8, 1, 20, 15, 0, 513000, tzinfo=<UTC>)

timezone.localtime(date)
# datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
7
frmdstryr

Cette réponse devrait être utile si vous ne souhaitez pas utiliser d'autres modules que datetime.

datetime.utcfromtimestamp(timestamp) renvoie un objet naïf datetime (non conscient). Les personnes conscientes sont conscientes du fuseau horaire et les naïfs ne le sont pas. Vous souhaitez en avoir une si vous souhaitez effectuer la conversion entre les fuseaux horaires (par exemple, entre l'heure UTC et l'heure locale).

Si vous n'êtes pas celui qui instancie la date pour commencer, mais que vous pouvez toujours créer un objet naïf datetime au format UTC, vous pouvez essayer ce code Python 3.x à convertir. il:

import datetime

d=datetime.datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") #Get your naive datetime object
d=d.replace(tzinfo=datetime.timezone.utc) #Convert it to an aware datetime object in UTC time.
d=d.astimezone() #Convert it to your local timezone (still aware)
print(d.strftime("%d %b %Y (%I:%M:%S:%f %p) %Z")) #Print it with a directive of choice

Veillez à ne pas présumer à tort que si votre fuseau horaire est actuellement MDT, l’heure avancée ne fonctionne pas avec le code ci-dessus, car il imprime MST. Vous noterez que si vous changez le mois en août, il imprimera MDT.

Un autre moyen facile d'obtenir un objet datetime conscient (également dans Python 3.x) consiste à le créer avec un fuseau horaire spécifié. Voici un exemple, en utilisant UTC:

import datetime, sys

aware_utc_dt_obj=datetime.datetime.now(datetime.timezone.utc) #create an aware datetime object
dt_obj_local=aware_utc_dt_obj.astimezone() #convert it to local time

#The following section is just code for a directive I made that I liked.
if sys.platform=="win32":
    directive="%#d %b %Y (%#I:%M:%S:%f %p) %Z"
else:
    directive="%-d %b %Y (%-I:%M:%S:%f %p) %Z"

print(dt_obj_local.strftime(directive))

Si vous utilisez Python 2.x, vous devrez probablement sous-classe datetime.tzinfo et l'utiliser pour vous aider à créer un objet datetime conscient, puisque datetime.timezone ne le fait pas. t existent dans Python 2.x.

7
Shule

Vous pouvez utiliser calendar.timegm pour convertir votre temps en secondes depuis Unix Epoch et time.localtime pour reconvertir:

import calendar
import time

time_Tuple = time.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
t = calendar.timegm(time_Tuple)

print time.ctime(t)

Donne Fri Jan 21 05:37:21 2011 (car je suis au fuseau horaire UTC + 03: 00).

1
myaut

Traditionnellement, je reporte cela au client - envoie les heures depuis le serveur sous forme d’horodatages ou d’un autre format de date/heure au format UTC, puis laisse le client déterminer le décalage du fuseau horaire et affiche ces données dans le fuseau horaire approprié.

Pour une application Web, cela est assez facile à faire en javascript - vous pouvez facilement comprendre le décalage horaire du navigateur en utilisant des méthodes intégrées, puis restituer correctement les données à partir du backend.

1
Matt Billenstein

Voici une version rapide et incorrecte qui utilise les paramètres des systèmes locaux pour calculer la différence de temps. REMARQUE: cela ne fonctionnera pas si vous devez convertir le fuseau horaire dans lequel votre système actuel ne fonctionne pas. Je l'ai testé avec les paramètres britanniques sous le fuseau horaire BST.

from datetime import datetime
def ConvertP4DateTimeToLocal(timestampValue):
   assert isinstance(timestampValue, int)

   # get the UTC time from the timestamp integer value.
   d = datetime.utcfromtimestamp( timestampValue )

   # calculate time difference from utcnow and the local system time reported by OS
   offset = datetime.now() - datetime.utcnow()

   # Add offset to UTC time and return it
   return d + offset
1
DelboyJay

À partir de la réponse ici , vous pouvez utiliser le module d'heure pour convertir d'utc en heure locale définie sur votre ordinateur:

utc_time = time.strptime("2018-12-13T10:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
utc_seconds = calendar.timegm(utc_time)
local_time = time.localtime(utc_seconds)
1
franksands
import datetime

def utc_str_to_local_str(utc_str: str, utc_format: str, local_format: str):
    """
    :param utc_str: UTC time string
    :param utc_format: format of UTC time string
    :param local_format: format of local time string
    :return: local time string
    """
    temp1 = datetime.datetime.strptime(utc_str, utc_format)
    temp2 = temp1.replace(tzinfo=datetime.timezone.utc)
    local_time = temp2.astimezone()
    return local_time.strftime(local_format)

utc = '2018-10-17T00:00:00.111Z'
utc_fmt = '%Y-%m-%dT%H:%M:%S.%fZ'
local_fmt = '%Y-%m-%dT%H:%M:%S+08:00'
local_string = utc_str_to_local_str(utc, utc_fmt, local_fmt)
print(local_string)   # 2018-10-17T08:00:00+08:00

par exemple, mon fuseau horaire est '+ 08:'. input utc = 2018-10-17T00: 00: 00.111Z, alors je vais obtenir une sortie = 2018-10-17T08: 00: 00 + 08:

0
Eureka Bing

Vous pouvez utiliser flèche

from datetime import datetime
import arrow

now = datetime.utcnow()

print(arrow.get(now).to('local').format())
# '2018-04-04 15:59:24+02:00'

vous pouvez nourrir arrow.get() avec n'importe quoi. horodatage, chaîne iso, etc.

0
d21d3q