Nunca he tenido que convertir el tiempo desde y hacia UTC. Hace poco recibí una solicitud para que mi aplicación tenga en cuenta la zona horaria, y me he estado ejecutando en círculos. Mucha información sobre la conversión de la hora local a UTC, que encontré bastante elemental (quizás también lo estoy haciendo mal), pero no puedo encontrar información sobre cómo convertir fácilmente la hora UTC a la zona horaria de los usuarios finales.
En pocas palabras, y la aplicación de Android me envía los datos (appengine app) y dentro de esos datos hay una marca de tiempo. Para almacenar ese sello de tiempo a tiempo de utc estoy usando:
datetime.utcfromtimestamp(timestamp)
Eso parece estar funcionando. Cuando mi aplicación almacena los datos, se almacenan con 5 horas de anticipación (estoy EST -5)
Los datos se almacenan en BigTable de appengine, y cuando se recuperan salen como una cadena como esta:
"2011-01-21 02:37:21"
¿Cómo convierto esta cadena a un DateTime en la zona horaria correcta de los usuarios?
Además, ¿cuál es el almacenamiento recomendado para la información de la zona horaria de un usuario? (¿Cómo suele almacenar información tz, es decir: “-5: 00” o “EST”, etc, etc.?) Estoy seguro de que la respuesta a mi primera pregunta podría contener un parámetro y la segunda respuesta.
Si no desea proporcionar sus propios objetos tzinfo
, consulte la biblioteca python-dateutil . Proporciona implementaciones tzinfo
sobre una base de datos de zoneinfo (Olson), de modo que puede hacer referencia a las reglas de zona horaria con un nombre un tanto canónico.
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)
Editar ejemplo ampliado para mostrar el uso de strptime
Editar 2 Uso de API fija para mostrar un mejor método de punto de entrada
Editar 3 métodos de detección automática incluidos para zonas horarias (Yarin)
Aquí hay un método resistente que no depende de ninguna biblioteca externa:
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
Esto evita los problemas de tiempo en el ejemplo de DelboyJay. Y los problemas de tiempo menores en la enmienda de Erik van Oosten.
Como una nota al pie de página interesante, el desplazamiento de la zona horaria calculado anteriormente puede diferir de la siguiente expresión aparentemente equivalente, probablemente debido a cambios en la regla de ahorro de luz diurna:
offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!
Actualización: este fragmento tiene la debilidad de utilizar el desplazamiento UTC de la hora actual, que puede diferir del desplazamiento UTC de la fecha y hora de entrada. Ver comentarios sobre esta respuesta para otra solución.
Para sortear los diferentes tiempos, toma el tiempo de la época del tiempo pasado. Esto es lo que hago:
def utc2local (utc): epoch = time.mktime(utc.timetuple()) offset = datetime.fromtimestamp (epoch) - datetime.utcfromtimestamp (epoch) return utc + offset
Consulte la documentación de datetime sobre objetos tzinfo . Tienes que implementar las zonas horarias para las que quieres mantenerte. Son ejemplos en la parte inferior de la documentación.
Aquí hay un ejemplo 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)
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
Si desea obtener el resultado correcto incluso para la hora que corresponde a una hora local ambigua (por ejemplo, durante una transición de horario de verano) y / o el desplazamiento utc local es diferente en diferentes momentos en su zona horaria local, entonces use las pytz
horarias de pytz
:
#!/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)
Si usa django, puede usar el método timezone.localtime (consulte 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=) timezone.localtime(date) # datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=)
Esta respuesta debería ser útil si no desea utilizar ningún otro módulo además de datetime
.
datetime.utcfromtimestamp(timestamp)
devuelve un objeto de datetime
ingenuo (no es consciente). Los que son conscientes son conscientes de la zona horaria, y los ingenuos no lo son. Desea una opción si desea convertir entre zonas horarias (por ejemplo, entre UTC y la hora local).
Para empezar, si no es el único con el que se crea la fecha, pero aún puede crear un objeto de datetime
ingenuo en la datetime
UTC, es posible que desee probar este código Python 3.x para convertirlo:
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
Tenga cuidado de no asumir erróneamente que si su zona horaria actualmente es MDT, el horario de verano no funciona con el código anterior ya que imprime MST. Notará que si cambia el mes a agosto, imprimirá MDT.
Otra forma fácil de obtener un objeto datetime
(también en Python 3.x) es crearlo con una zona horaria especificada para comenzar. Aquí hay un ejemplo, usando 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 usa Python 2.x, probablemente tendrá que subclasificar datetime.tzinfo
y usarlo para ayudarlo a crear un objeto datetime
consciente, ya que datetime.timezone
no existe en Python 2.x.
Tradicionalmente, difiero esto al frontend: envío los tiempos desde el backend como marcas de tiempo o algún otro formato de fecha y hora en UTC, luego dejo que el cliente calcule el desplazamiento de la zona horaria y presente estos datos en la zona horaria adecuada.
Para una aplicación web, esto es bastante fácil de hacer en javascript: puede descifrar el desplazamiento de la zona horaria del navegador con bastante facilidad utilizando métodos incorporados y luego renderizar los datos desde el backend correctamente.
Aquí hay una versión rápida y sucia que usa la configuración de los sistemas locales para calcular la diferencia horaria. NOTA: Esto no funcionará si necesita convertir a una zona horaria en la que su sistema actual no se está ejecutando. He probado esto con la configuración del Reino Unido bajo la zona horaria 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
Puede usar calendar.timegm
para convertir su tiempo a segundos desde la época de Unix y time.localtime
para volver a convertir:
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)
Da Fri Jan 21 05:37:21 2011
(porque estoy en UTC + 03: 00 zona horaria).
Puedes usar flecha
from datetime import datetime import arrow now = datetime.utcnow() print(arrow.get(now).to('local').format()) # '2018-04-04 15:59:24+02:00'
Puedes alimentar a arrow.get()
con cualquier cosa. marca de tiempo, cadena iso etc
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
por ejemplo, mi zona horaria es ‘ +08: 00 ‘. entrada utc = 2018-10-17T00: 00: 00.111Z , luego obtendré salida = 2018-10-17T08: 00: 00 + 08: 00
Desde la respuesta aquí , puede usar el módulo de hora para convertir de utc a la hora local establecida en su computadora:
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)