change - set timezone to datetime python
Convierta un horario de UTC de python a un horario local utilizando solo la biblioteca estándar de Python. (8)
Tengo una instancia de python datetime que se creó usando datetime.utcnow () y persistió en la base de datos.
Para mostrar, me gustaría convertir la instancia de fecha y hora recuperada de la base de datos a hora local utilizando la zona horaria local predeterminada (es decir, como si la fecha y hora se hubiera creado usando datetime.now ()).
¿Cómo puedo convertir la fecha y hora de UTC en una fecha de hora local utilizando solo la biblioteca estándar de Python (por ejemplo, no dependencia de pytz)?
Parece que una solución sería usar datetime.astimezone (tz), pero ¿cómo obtendría la zona horaria local predeterminada?
Basándose en el comentario de Alexei. Esto también debería funcionar para 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)
Creo que lo descubrí: calcula el número de segundos desde epoch, luego convierte a un timzeone local usando time.localtime, y luego convierte el tiempo struct de nuevo 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 )
Aplica el horario de verano / invierno correctamente:
>>> 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)
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.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
Nota: tiene en cuenta el horario de verano y el cambio reciente de la compensación utc para la zona horaria MSK.
No sé si las soluciones que no son de pytz funcionan en Windows.
La biblioteca estándar de Python no viene con ninguna implementación de tzinfo
. Siempre he considerado esto como una falla sorprendente del módulo de fecha y hora.
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.
La forma más fácil que he encontrado es obtener el desplazamiento de tiempo de donde se encuentra, 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.
No puede hacerlo solo con la biblioteca estándar, ya que la biblioteca estándar no tiene zonas horarias. Necesita 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, puedes hacerlo sin pytz o dateutil implementando tus propias zonas horarias. Pero eso sería una tontería.
No puedes hacerlo con la biblioteca estándar. Usando el módulo de pytz puedes convertir cualquier objeto de fecha / 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 en cualquier otra zona horaria, primero debe convertirlo en un objeto datetime consciente . Puede usar el método de replace
para convertir un objeto datetime ingenuo a un objeto datetime 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 de 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()
Porque now
método devuelve la fecha y la hora actuales, por lo que primero debe tener en cuenta la zona horaria del objeto datetime. La función de localize
convierte un objeto datetime ingenuo en un objeto datetime que reconoce la zona horaria. Luego puede 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)
Una forma simple (pero quizás 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