Convertir datetime.date a la marca de hora UTC en Python

Estoy tratando con fechas en Python y necesito convertirlas a marcas de tiempo UTC para ser utilizadas dentro de Javascript. El siguiente código no funciona:

>>> d = datetime.date(2011,01,01) >>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple())) datetime.datetime(2010, 12, 31, 23, 0) 

La conversión del objeto de fecha primero a fecha y hora tampoco ayuda. Probé el ejemplo en este enlace de, pero:

 from pytz import utc, timezone from datetime import datetime from time import mktime input_date = datetime(year=2011, month=1, day=15) 

y ahora ya sea:

 mktime(utc.localize(input_date).utctimetuple()) 

o

 mktime(timezone('US/Eastern').localize(input_date).utctimetuple()) 

funciona.

Pregunta tan general: ¿cómo puedo convertir una fecha en segundos desde la época según UTC?

Si d = date(2011, 1, 1) está en UTC:

 >>> from datetime import datetime, date >>> import calendar >>> timestamp1 = calendar.timegm(d.timetuple()) >>> datetime.utcfromtimestamp(timestamp1) datetime.datetime(2011, 1, 1, 0, 0) 

Si d está en la zona horaria local:

 >>> import time >>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE >>> datetime.fromtimestamp(timestamp2) datetime.datetime(2011, 1, 1, 0, 0) 

timestamp1 y timestamp2 pueden diferir si la medianoche en la zona horaria local no es la misma hora que la medianoche en UTC.

mktime() puede devolver un resultado incorrecto si d corresponde a una hora local ambigua (por ejemplo, durante la transición de horario de verano) o si d es una fecha pasada (futura) en la que el desplazamiento de utc podría haber sido diferente y el C mktime() no tiene acceso a la base de datos tz en la plataforma dada. Puede usar el módulo pytz (por ejemplo, a través de tzlocal.get_localzone() ) para obtener acceso a la base de datos tz en todas las plataformas . Además, utcfromtimestamp() puede fallar y mktime() puede devolver una marca de tiempo que no sea POSIX si se usa la zona horaria "right" .


Para convertir el objeto datetime.date que representa la fecha en UTC sin calendar.timegm() :

 DAY = 24*60*60 # POSIX day in seconds (exact value) timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * DAY timestamp = (utc_date - date(1970, 1, 1)).days * DAY 

¿Cómo puedo obtener una fecha convertida a segundos desde la época según UTC?

Para convertir el objeto datetime.datetime (no datetime.date ) que ya representa el tiempo en UTC a la marca de tiempo POSIX correspondiente (un float ).

Python 3.3 o superior

datetime.timestamp() :

 from datetime import timezone timestamp = dt.replace(tzinfo=timezone.utc).timestamp() 

Nota: es necesario proporcionar timezone.utc explícitamente; de ​​lo contrario, .timestamp() asume que su objeto de fecha y hora ingenuo está en la zona horaria local.

Python 3 (<3.3)

De los documentos para datetime.utcfromtimestamp() :

No hay un método para obtener la marca de tiempo de una instancia de fecha y hora, pero la marca de hora POSIX correspondiente a una instancia de fecha y hora dt se puede calcular fácilmente de la siguiente manera. Para un ingenuo dt:

 timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1) 

Y para un dt consciente:

 timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1) 

Lectura interesante: la hora de la época frente a la hora del día sobre la diferencia entre ¿Qué hora es? y cuantos segundos han transcurrido?

Ver también: datetime necesita un método “epoch”

Python 2

Para adaptar el código anterior para Python 2:

 timestamp = (dt - datetime(1970, 1, 1)).total_seconds() 

donde timedelta.total_seconds() es equivalente a (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 computado con la división verdadera habilitada.

Ejemplo

 from __future__ import division from datetime import datetime, timedelta def totimestamp(dt, epoch=datetime(1970,1,1)): td = dt - epoch # return td.total_seconds() return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6 now = datetime.utcnow() print now print totimestamp(now) 

Cuidado con las cuestiones de punto flotante .

Salida

 2012-01-08 15:34:10.022403 1326036850.02 

Cómo convertir un objeto datetime consciente a la marca de tiempo POSIX

 assert dt.tzinfo is not None and dt.utcoffset() is not None timestamp = dt.timestamp() # Python 3.3+ 

En Python 3:

 from datetime import datetime, timedelta, timezone epoch = datetime(1970, 1, 1, tzinfo=timezone.utc) timestamp = (dt - epoch) / timedelta(seconds=1) integer_timestamp = (dt - epoch) // timedelta(seconds=1) 

En Python 2:

 # utc time = local time - utc offset utc_naive = dt.replace(tzinfo=None) - dt.utcoffset() timestamp = (utc_naive - datetime(1970, 1, 1)).total_seconds() 

Solo para sistemas UNIX :

 >>> import datetime >>> d = datetime.date(2011,01,01) >>> d.strftime("%s") # <-- THIS IS THE CODE YOU WANT '1293832800' 

Nota 1: dizzyf observó que esto se aplica a las zonas horarias localizadas . No usar en producción.

Nota 2: Jakub Narębski observó que esto ignora la información de la zona horaria, incluso en el caso de fecha y hora con reconocimiento de desplazamiento (probado para Python 2.7).

  • Supuesto 1: está intentando convertir una fecha en una marca de tiempo, sin embargo, dado que una fecha cubre un período de 24 horas, no hay una sola marca de tiempo que represente esa fecha. Asumiré que desea representar la marca de tiempo de esa fecha a la medianoche (00: 00: 00.000).

  • Supuesto 2: La fecha que presenta no está asociada con una zona horaria en particular, sin embargo, desea determinar el desplazamiento desde una zona horaria en particular (UTC). Sin saber la zona horaria en la que se encuentra la fecha, no es posible calcular una marca de tiempo para una zona horaria específica. Asumiré que desea tratar la fecha como si estuviera en la zona horaria del sistema local.

Primero, puede convertir la instancia de fecha en una tupla que representa los diversos componentes de tiempo usando el miembro timetuple() :

 dtt = d.timetuple() # time.struct_time(tm_year=2011, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1) 

Luego puedes convertir eso en una marca de tiempo usando time.mktime :

 ts = time.mktime(dtt) # 1293868800.0 

Puede verificar este método probándolo con el propio tiempo de época (1970-01-01), en cuyo caso la función debería devolver el desplazamiento de zona horaria para la zona horaria local en esa fecha:

 d = datetime.date(1970,1,1) dtt = d.timetuple() # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=-1) ts = time.mktime(dtt) # 28800.0 

28800.0 son 8 horas, lo que sería correcto para la zona horaria del Pacífico (donde estoy).

siga el documento python2.7, tiene que usar calendar.timegm () en lugar de time.mktime ()

 >>> d = datetime.date(2011,01,01) >>> datetime.datetime.utcfromtimestamp(calendar.timegm(d.timetuple())) datetime.datetime(2011, 1, 1, 0, 0) 

Definí mis dos funciones

  • utc_time2datetime (utc_time, tz = Ninguno)
  • datetime2utc_time (datetime)

aquí:

 import time import datetime from pytz import timezone import calendar import pytz def utc_time2datetime(utc_time, tz=None): # convert utc time to utc datetime utc_datetime = datetime.datetime.fromtimestamp(utc_time) # add time zone to utc datetime if tz is None: tz_datetime = utc_datetime.astimezone(timezone('utc')) else: tz_datetime = utc_datetime.astimezone(tz) return tz_datetime def datetime2utc_time(datetime): # add utc time zone if no time zone is set if datetime.tzinfo is None: datetime = datetime.replace(tzinfo=timezone('utc')) # convert to utc time zone from whatever time zone the datetime is set to utc_datetime = datetime.astimezone(timezone('utc')).replace(tzinfo=None) # create a time tuple from datetime utc_timetuple = utc_datetime.timetuple() # create a time element from the tuple an add microseconds utc_time = calendar.timegm(utc_timetuple) + datetime.microsecond / 1E6 return utc_time 

La pregunta es un poco confusa. las marcas de tiempo no son UTC, son una cosa de Unix. la fecha podría ser UTC? asumiendo que lo es, y si estás usando Python 3.2+, simple-date hace que esto sea trivial:

 >>> SimpleDate(date(2011,1,1), tz='utc').timestamp 1293840000.0 

Si realmente tiene el año, el mes y el día, no necesita crear la date :

 >>> SimpleDate(2011,1,1, tz='utc').timestamp 1293840000.0 

y si la fecha está en otra zona horaria (esto es importante porque estamos asumiendo la medianoche sin un tiempo asociado):

 >>> SimpleDate(date(2011,1,1), tz='America/New_York').timestamp 1293858000.0 

[la idea de la fecha simple es recostackr todas las cosas relacionadas con la fecha y la hora de Python en una clase coherente, para que pueda realizar cualquier conversión. así, por ejemplo, también irá a la inversa:

 >>> SimpleDate(1293858000, tz='utc').date datetime.date(2011, 1, 1) 

]

Usando el paquete de flechas :

 >>> import arrow >>> arrow.get(2010, 12, 31).timestamp 1293753600 >>> time.gmtime(1293753600) time.struct_time(tm_year=2010, tm_mon=12, tm_mday=31, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=365, tm_isdst=0) 

Una cadena de tiempo completa contiene:

  • fecha
  • hora
  • utcoffset [+HHMM or -HHMM]

Por ejemplo:

1970-01-01 06:00:00 +0500 == 1970-01-01 01:00:00 +0000 == UNIX timestamp:3600

 $ python3 >>> from datetime import datetime >>> from calendar import timegm >>> tm = '1970-01-01 06:00:00 +0500' >>> fmt = '%Y-%m-%d %H:%M:%S %z' >>> timegm(datetime.strptime(tm, fmt).utctimetuple()) 3600 

Nota:

UNIX timestamp es un número de punto flotante expresado en segundos desde la época, en UTC .


Editar:

 $ python3 >>> from datetime import datetime, timezone, timedelta >>> from calendar import timegm >>> dt = datetime(1970, 1, 1, 6, 0) >>> tz = timezone(timedelta(hours=5)) >>> timegm(dt.replace(tzinfo=tz).utctimetuple()) 3600