¿Convertir un datetime UTC de python a un datetime local usando solo la biblioteca estándar de python?

Tengo una instancia datetime de Python que se creó utilizando datetime.utcnow () y persistió en la base de datos.

Para la visualización, me gustaría convertir la instancia de datetime recuperada de la base de datos a datetime local usando la zona horaria local predeterminada (es decir, como si el datetime se creara usando datetime.now ()).

¿Cómo puedo convertir el datetime UTC a un datetime local usando solo la biblioteca estándar de python (por ejemplo, sin dependencia de pytz)?

Parece que una solución sería usar datetime.astimezone (tz), pero ¿cómo obtendría la zona horaria local predeterminada?

En Python 3.3+:

from datetime import datetime, 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) 

Usando pytz (ambos 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 

Ejemplo

 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())) 

Salida

Python 3.3

 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 

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 

Nota: toma en cuenta el horario de verano y el cambio reciente de la compensación de utc para la zona horaria de MSK.

No sé si las soluciones que no son pytz funcionan en Windows.

No puede hacerlo solo con la biblioteca estándar, ya que la biblioteca estándar no tiene zonas horarias. Necesitas pytz o 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()) 

O bien, puede hacerlo sin pytz o dateutil implementando sus propias zonas horarias. Pero eso sería una tontería.

Creo que lo descubrí: calcula el número de segundos desde la época, luego se convierte en un timzeone local usando time.localtime, y luego convierte la estructura de tiempo de nuevo en una fecha y hora …

 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 ) 

Aplica correctamente el horario de verano / invierno DST:

 >>> 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) 

No puedes hacerlo con la biblioteca estándar. Usando el módulo pytz puede convertir cualquier objeto de fecha y hora ingenuo / consciente a cualquier otra zona horaria. Veamos algunos ejemplos usando Python 3.

Objetos ingenuos creados a través del método de clase utcnow()

Para convertir un objeto ingenuo a cualquier otra zona horaria, primero debe convertirlo en un objeto datetime. Puede utilizar el método de replace para convertir un objeto de fecha y hora ingenuo en un objeto de fecha y hora consciente . Luego, para convertir un objeto datetime consciente en cualquier otra zona horaria, puede usar el método astimezone .

La variable pytz.all_timezones le proporciona la lista de todas las zonas horarias disponibles en el módulo 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) 

Objetos ingenuos creados a través del método de clase now()

Debido a que now método devuelve la fecha y la hora actuales, por lo tanto, primero debe hacer que la zona horaria del objeto datetime sea consciente. La función de localize convierte un objeto de fecha y hora ingenuo en un objeto de fecha y hora compatible con la zona horaria. Luego puedes usar el método astimezone para convertirlo en otra zona horaria.

 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 biblioteca estándar de Python no viene con ninguna implementación tzinfo . Siempre he considerado esto como un defecto sorprendente del módulo datetime.

La documentación para la clase tzinfo viene con algunos ejemplos útiles. Busque el bloque de código grande al final de la sección.

Sobre la base del comentario de Alexei. Esto debería funcionar para DST también.

 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) 

Una forma simple (pero tal vez defectuosa) que funciona en Python 2 y 3:

 import time import datetime def utc_to_local(dt): return dt - datetime.timedelta(seconds = time.timezone) 

Su ventaja es que es trivial escribir una función inversa.

La forma más fácil que he encontrado es obtener el desplazamiento de tiempo de donde estás y luego restarlo de la hora.

 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 

Esto funciona para mí, en Python 3.5.2.

Aquí hay otra forma de cambiar la zona horaria en el formato de fecha y hora (sé que desperdicié mi energía en esto, pero no vi esta página, así que no sé cómo) sin el mínimo. y seg. Porque no lo necesito para mi proyecto:

 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) 

Esta es una manera terrible de hacerlo, pero evita crear una definición. Cumple con el requisito de seguir con la biblioteca básica de 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])