J'ai une instance python datetime qui a été créée à l'aide de datetime.utcnow () et persistée dans la base de données.
Pour l'affichage, je voudrais convertir l'instance datetime extraite de la base de données en datetime local en utilisant le fuseau horaire local par défaut (c'est-à-dire, comme si le datetime était créé à l'aide de datetime.now ()).
Comment puis-je convertir le datetime UTC en un datetime local en utilisant uniquement la bibliothèque standard Python (par exemple, aucune dépendance pytz)?
Il semble qu'une solution consisterait à utiliser datetime.astimezone (tz), mais comment obtiendriez-vous le fuseau horaire local par défaut?
Je pense l'avoir compris: calcule le nombre de secondes depuis Epoch, puis convertit le timzeone local en utilisant time.localtime, puis reconvertit la structure de l'heure en un 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é/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)
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 Python 2/3):
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
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()))
2010-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
2010-06-06 21:29:07.730000
2010-12-06 20:29:07.730000
2012-11-08 14:19:50.093911
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
Remarque: il tient compte de l'heure d'été et de la modification récente du décalage utc du fuseau horaire MSK.
Je ne sais pas si les solutions non-pytz fonctionnent sous Windows.
Vous ne pouvez pas le faire uniquement avec la bibliothèque standard car celle-ci n’a pas de fuseau horaire. Vous avez besoin de 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 mettant en place vos propres fuseaux horaires. Mais ce serait idiot.
Vous ne pouvez pas le faire avec une bibliothèque standard. En utilisant pytz module, vous pouvez convertir n’importe quel objet datetime naïf/conscient en n’importe quel fuseau horaire. Voyons quelques exemples utilisant Python 3.
Objets naïfs créés par la méthode de classe
utcnow()
Pour convertir un objet naive en un autre fuseau horaire, vous devez d’abord le convertir en objet aware datetime. Vous pouvez utiliser la méthode replace
pour convertir un objet naive datetime en un objet aware datetime. Ensuite, pour convertir un objet aware datetime 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 le module pytz.
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 rendre l'objet fuseau horaire conscient de la date. La fonction localize
convertit un objet naive datetime en un objet datetime compatible avec un fuseau horaire. Ensuite, vous pouvez utiliser la méthode astimezone
pour le 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)
La bibliothèque Python standard n’est livrée avec aucune implémentation de tzinfo
. J'ai toujours considéré cela comme une faiblesse surprenante du module datetime.
La documentation de la classe tzinfo est fournie avec des exemples utiles. Recherchez le gros bloc de code à la fin de la section.
S'appuyant sur le commentaire d'Alexei. Cela devrait fonctionner aussi pour DST.
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)
Voici une autre façon de changer le fuseau horaire au format datetime (je sais que j'ai perdu mon énergie à ce sujet mais je n'ai pas vu cette page, donc je ne sais pas comment) sans min. et sec. car 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:
if not year%4==0:
if day >= 29:
day = 1
month += 1
if month > 12:
year += 1
else:
if day >= 28:
day = 1
month += 1
if month > 12:
year += 1
return datetime(int(year), int(month), int(day), int(hour), 00)
Une manière simple (mais peut-être imparfaite) 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
Le moyen le plus simple que j'ai trouvé est d'obtenir le décalage horaire de l'endroit où vous êtes, puis soustrayez cela 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, dans Python 3.5.2.
C'est une façon terrible de le faire mais cela évite de créer une définition. Il remplit l'obligation de s'en tenir à la bibliothèque de base Python3.
# Adjust from UST to Eastern Standard Time (dynamic)
# df.my_localtime should already be in datetime format, so just in case
df['my_localtime'] = pd.to_datetime.df['my_localtime']
df['my_localtime'] = df['my_localtime'].dt.tz_localize('UTC').dt.tz_convert('America/New_York').astype(str)
df['my_localtime'] = pd.to_datetime(df.my_localtime.str[:-6])