Convertir un datetime UTC python en un datetime local en utilisant uniquement la bibliothèque standard Python?
J'ai une instance Python datetime qui a été créée en utilisant datetime.utcnow() et persistant dans la base de données.
Pour l'affichage, Je voudrais convertir l'instance datetime extraite de la base de données en datetime locale en utilisant le fuseau horaire local par défaut (c'est-à-dire, comme si le datetime avait été créé en utilisant datetime.maintenant()).
Comment puis-je convertir le datetime UTC en un datetime local en utilisant uniquement la bibliothèque standard Python (par exemple, pas de dépendance pytz)?
, Il semble qu'une solution serait d'utiliser datetime.astimezone (tz), mais comment obtiendriez-vous le fuseau horaire local par défaut?
9 réponses
En Python 3.3+:
from datetime import timezone
def utc_to_local(utc_dt):
return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)
En Python 2/3:
import calendar
from datetime import datetime, timedelta
def utc_to_local(utc_dt):
# get integer timestamp to avoid precision lost
timestamp = calendar.timegm(utc_dt.timetuple())
local_dt = datetime.fromtimestamp(timestamp)
assert utc_dt.resolution >= timedelta(microseconds=1)
return local_dt.replace(microsecond=utc_dt.microsecond)
En utilisant pytz
(les deux 2/3 Python):
import pytz
local_tz = pytz.timezone('Europe/Moscow') # use your local timezone name here
# NOTE: pytz.reference.LocalTimezone() would produce wrong result here
## You could use `tzlocal` module to get local timezone on Unix and Win32
# from tzlocal import get_localzone # $ pip install tzlocal
# # get local timezone
# local_tz = get_localzone()
def utc_to_local(utc_dt):
local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
return local_tz.normalize(local_dt) # .normalize might be unnecessary
Exemple
def aslocaltimestr(utc_dt):
return utc_to_local(utc_dt).strftime('%Y-%m-%d %H:%M:%S.%f %Z%z')
print(aslocaltimestr(datetime(2010, 6, 6, 17, 29, 7, 730000)))
print(aslocaltimestr(datetime(2010, 12, 6, 17, 29, 7, 730000)))
print(aslocaltimestr(datetime.utcnow()))
Sortie
Python 3.32010-06-06 21:29:07.730000 MSD+0400
2010-12-06 20:29:07.730000 MSK+0300
2012-11-08 14:19:50.093745 MSK+0400
Python 2
2010-06-06 21:29:07.730000
2010-12-06 20:29:07.730000
2012-11-08 14:19:50.093911
pytz
2010-06-06 21:29:07.730000 MSD+0400
2010-12-06 20:29:07.730000 MSK+0300
2012-11-08 14:19:50.146917 MSK+0400
Note: il prend en compte DST et le changement récent de décalage utc pour le fuseau horaire MSK.
Je ne sais pas si les solutions non-pytz fonctionnent sur Windows.
Vous ne pouvez pas le faire avec seulement la bibliothèque standard car la bibliothèque standard n'a pas de fuseaux horaires. Vous avez besoin d' pytz ou dateutil.
>>> from datetime import datetime
>>> now = datetime.utcnow()
>>> from dateutil import tz
>>> HERE = tz.tzlocal()
>>> UTC = tz.gettz('UTC')
The Conversion:
>>> gmt = now.replace(tzinfo=UTC)
>>> gmt.astimezone(HERE)
datetime.datetime(2010, 12, 30, 15, 51, 22, 114668, tzinfo=tzlocal())
Ou bien, vous pouvez le faire sans pytz ou dateutil en implémentant vos propres fuseaux horaires. Mais ce serait ridicule.
Je pense que je l'ai compris: calcule le nombre de secondes depuis l'époque, puis convertit en un timzeone local en utilisant le temps.localtime, puis convertit la structure time en datetime...
EPOCH_DATETIME = datetime.datetime(1970,1,1)
SECONDS_PER_DAY = 24*60*60
def utc_to_local_datetime( utc_datetime ):
delta = utc_datetime - EPOCH_DATETIME
utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds
time_struct = time.localtime( utc_epoch )
dt_args = time_struct[:6] + (delta.microseconds,)
return datetime.datetime( *dt_args )
Il applique correctement l'heure d'été/d'hiver:
>>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 6, 6, 19, 29, 7, 730000)
>>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 12, 6, 18, 29, 7, 730000)
La bibliothèque Python standard ne contient aucune implémentation tzinfo
. J'ai toujours considéré cela comme une lacune surprenante du module datetime.
La documentation pour la classe tzinfo vient avec quelques exemples utiles. Chercher le grand bloc de code à la fin de la section.
Vous ne pouvez pas le faire avec la bibliothèque standard. En utilisant le module pytz , Vous pouvez convertir n'importe quel objet DateTime naïf/conscient en n'importe quel autre fuseau horaire. Voyons quelques exemples en utilisant Python 3.
Objets naïfs créés par la méthode de classe
utcnow()
Pour convertir un naïf objet à un autre fuseau horaire, vous devez d'abord le convertir en conscient objet datetime. Vous pouvez utiliser la méthode replace
pour convertir un objetnaïf datetime en un objet datetimeconscient . Ensuite, pour convertir un objet datetimeaware en un autre fuseau horaire, vous pouvez utiliser la méthode astimezone
.
La variable pytz.all_timezones
vous donne la liste de tous les fuseaux horaires disponibles dans pytz module.
import datetime,pytz
dtobj1=datetime.datetime.utcnow() #utcnow class method
print(dtobj1)
dtobj3=dtobj1.replace(tzinfo=pytz.UTC) #replace method
dtobj_hongkong=dtobj3.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
print(dtobj_hongkong)
Objets naïfs créés par la méthode de classe
now()
Étant donné que la méthode now
renvoie la date et l'heure actuelles, vous devez d'abord informer le fuseau horaire de l'objet datetime. La fonction localize
convertit un naïf objet datetime dans un objet datetime sensible au fuseau horaire. Ensuite, vous pouvez utiliser la méthode astimezone
pour la convertir en un autre fuseau horaire.
dtobj2=datetime.datetime.now()
mytimezone=pytz.timezone("Europe/Vienna") #my current timezone
dtobj4=mytimezone.localize(dtobj2) #localize function
dtobj_hongkong=dtobj4.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
print(dtobj_hongkong)
S'appuyant sur le commentaire D'Alexei. Cela devrait fonctionner pour L'heure D'été aussi.
import time
import datetime
def utc_to_local(dt):
if time.localtime().tm_isdst:
return dt - datetime.timedelta(seconds = time.altzone)
else:
return dt - datetime.timedelta(seconds = time.timezone)
Un moyen simple (mais peut-être défectueux) qui fonctionne en Python 2 et 3:
import time
import datetime
def utc_to_local(dt):
return dt - datetime.timedelta(seconds = time.timezone)
Son avantage est qu'il est trivial d'écrire une fonction inverse
La façon La plus simple que j'ai trouvé est d'obtenir le décalage dans le temps d'où vous, alors déduire de l'heure.
def format_time(ts,offset):
if not ts.hour >= offset:
ts = ts.replace(day=ts.day-1)
ts = ts.replace(hour=ts.hour-offset)
else:
ts = ts.replace(hour=ts.hour-offset)
return ts
Cela fonctionne pour moi, en python 3.5.2.
Voici une autre façon de changer le fuseau horaire au format datetime (je sais que j'ai gaspillé mon énergie là-dessus mais je n'ai pas vu cette page donc je ne sais pas comment) sans min. et sec. parce que je n'en ai pas besoin pour mon projet:
def change_time_zone(year, month, day, hour):
hour = hour + 7 #<-- difference
if hour >= 24:
difference = hour - 24
hour = difference
day += 1
long_months = [1, 3, 5, 7, 8, 10, 12]
short_months = [4, 6, 9, 11]
if month in short_months:
if day >= 30:
day = 1
month += 1
if month > 12:
year += 1
elif month in long_months:
if day >= 31:
day = 1
month += 1
if month > 12:
year += 1
elif month == 2:
leap_years = [2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048]
if year in leap_years:
if day >= 29:
day = 1
month += 1
if month > 12:
year += 1
elif year not in leap_years:
if day >= 28:
day = 1
month += 1
if month > 12:
year += 1
return datetime(int(year), int(month), int(day), int(hour), 00)