Convierta python datetime a epoch con strftime

209

Tengo un tiempo en UTC a partir del cual quiero la cantidad de segundos desde la época.

Estoy usando strftime para convertirlo a la cantidad de segundos. Tomando el 1 de abril de 2012 como ejemplo.

>>>datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'

El 1 de abril de 2012 UTC de la época es 1333238400, pero lo anterior devuelve 1333234800, que es diferente en 1 hora.

Entonces parece que ese tiempo de espera está tomando en cuenta el tiempo de mi sistema y aplica un cambio de zona horaria en algún lugar. ¿Pensé que la fecha y hora era puramente ingenua?

¿Cómo puedo evitar eso? Si es posible, evite importar otras bibliotecas a menos que sea estándar. (Tengo problemas de portabilidad).

Navidad
fuente
11
¿Soy el único que observa que usa literales octales en los números?
Fish Monitor
3
Python 3.3+ más reciente tienedatetime.datetime.timestamp(datetime.datetime.utcnow())
MarkHu

Respuestas:

390

Si desea convertir una fecha y hora de Python a segundos desde época, puede hacerlo explícitamente:

>>> (datetime.datetime(2012,04,01,0,0) - datetime.datetime(1970,1,1)).total_seconds()
1333238400.0

En Python 3.3+ puedes usar timestamp()en su lugar:

>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0

Por qué no deberías usar datetime.strftime('%s')

Python en realidad no admite% s como argumento para strftime (si marca http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior no está en la lista), el único la razón por la que funciona es porque Python está pasando la información al tiempo de ejecución de su sistema, que utiliza su zona horaria local.

>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
jleahy
fuente
77
Me he vuelto loco tratando de entender por qué veo mucho el tiempo de espera ("% s"), pero no está en los documentos. Gracias por nada de esto!
Jonathan Vanasco
54
no use .strftime("%s"): no es compatible, no es portátil, puede producir silenciosamente un resultado incorrecto para un objeto de fecha y hora consciente, falla si la entrada está en UTC (como en la pregunta) pero la zona horaria local no es UTC
jfs
2
@earthmeLon Tu horquillado está mal. Las timedeltas (hechas restando dos fechas y horas) tienen total_segundos, pero las horas y horas no.
jleahy
2
Esto no funciona para mí:AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'
Michael
3
@Michael Esa función es nueva en Python 2.7, debe estar utilizando una versión anterior. Para versiones anteriores a 2.7 que puedes hacer td.seconds + td.days*24*3600. Esto descarta la parte de microsegundos.
jleahy
100

Tuve serios problemas con Timezones y demás. La forma en que Python maneja todo lo que resulta ser bastante confuso (para mí). Las cosas parecen estar funcionando bien usando el módulo de calendario (ver enlaces 1 , 2 , 3 y 4 ).

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400
BorrajaX
fuente
77
+1 porque es la única respuesta que funciona para la entrada en la pregunta.
jfs
¿Es esto portátil?
benjaminz
1
Esto debe marcarse como la respuesta legítima, ya que esto responde a la preocupación en cuestión. vnice kudos
Leo Prince
2
Esto "funciona", pero tenga en cuenta que la pregunta indicaba: "Tengo un horario en UTC" Este método siempre utilizará la zona horaria local del sistema. No hay forma de especificar una zona horaria. Si aprilFirsten este ejemplo fuera una instancia 'consciente' y utilizara una zona horaria diferente de la zona horaria del sistema, el resultado no sería correcto (la zona horaria se pierde en la timetuple()llamada). Para obtener la respuesta correcta para una fecha y hora "consciente", puede usarla awaredt.timestamp()en Python 3. reciente. Para Python 2 es más difícil; Una forma es utilizar la arrowbiblioteca. arrow.get(awaredt).timestampLo hará bien.
Adam Williamson
1
Buen punto, @AdamWilliamson, pero el código en el ejemplo no está localizando el datetimeobjeto, así que supuse que "Tengo un tiempo en UTC" significaba que el OP tenía un datetimeobjeto desconocido que se suponía que estaba en UTC para lo que quería para obtener un epoch(si datetimeresulta ser consciente de TZ esto podría, de hecho, cambiar las cosas). Además, tenga en cuenta que esta respuesta tiene casi 8 años y han sucedido muchas cosas desde entonces ( arrowfue lanzado en 2013, por ejemplo)
BorrajaX
35
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())
srossross
fuente
1
es una forma incorrecta de escribir time.time()( mktime()puede fallar durante las transiciones DST mientras time.time()continúa funcionando). Y no responde la pregunta a menos que la zona horaria local sea UTC (la entrada en la pregunta está en UTC). Incluso si la entrada representara una hora local, entonces mktime()también puede fallar para fechas pasadas / futuras si no usa la base de datos tz y si la zona horaria local puede tener diferentes compensaciones de utc a lo largo de los años, por ejemplo, Europa / Moscú en 2010-2015 - - use la hora UTC (como en la pregunta) u objetos datetime con reconocimiento de zona horaria en su lugar.
jfs
Aquí hay más problemas con la conversión de una hora local (como devuelta por .now()) a la marca de tiempo de época (devuelta por mktime()) . Si lo lees; a entender por qué la entrada UTC (utilizado en la pregunta) es (mucho) más preferible que un objeto de fecha y hora ingenua que representa la hora local
JFS
14
import time
from datetime import datetime
now = datetime.now()

# same as above except keeps microseconds
time.mktime(now.timetuple()) + now.microsecond * 1e-6

(Lo siento, no me dejaba comentar sobre la respuesta existente)

Charles Plager
fuente
Esto se debe a que time.mktime no tiene en cuenta la parte del microsegundo, ¿verdad?
Eduardo
1
Correcto. La estructura de tupla de tiempo (basada en el puntal C) no tiene espacio para microsegundos, por lo que debemos tomar la información del objeto datetime y agregarla al final.
Charles Plager
En mis máquinas, esto funciona correctamente aunque mi zona horaria es ET.
Charles Plager
1
Esto le dará diferentes marcas de tiempo en diferentes sistemas según la hora local del sistema.
Yousaf
6

Si solo necesita una marca de tiempo en tiempo unix / epoch, esta línea funciona:

created_timestamp = int((datetime.datetime.now() - datetime.datetime(1970,1,1)).total_seconds())
>>> created_timestamp
1522942073L

y depende solo de datetime trabajos en python2 y python3

Marc Maxmeister
fuente
3

Esto funciona en Python 2 y 3:

>>> import time
>>> import calendar
>>> calendar.timegm(time.gmtime())
1504917998

Simplemente siguiendo los documentos oficiales ... https://docs.python.org/2/library/time.html#module-time

Luis Pollo
fuente
1) Esto supone que desea convertir ahora, no un objeto aleatorio de fecha y hora. 2) No necesitas calendario. time.mktime (randomDateTime.timetuple ()) + randomDateTime.microsecond * 1e-6
Charles Plager
@CharlesPlager time.mktime es incorrecto; interpreta el argumento en la zona horaria local, mientras que el OP quiere que la hora se interprete en UTC (como hace calendar.timegm).
stewbasic
Esta es la respuesta más precisa para mí, si está buscando convertir su tiempo en GMT y desea mantenerlo así en la conversión a la marca de tiempo de época.
Yousaf
Simplemente siguiendo su respuesta, calendar.timegm (datetime.strptime ("2019-05-03T05: 40: 09.770494 + 00: 00" [: 16], '% Y-% m-% dT% H:% M'). timetuple ()) Tengo una marca de tiempo en utc y no importa en qué sistema se ejecute, me da la marca de tiempo correcta, el truco es usar strptime.timetumple
Yousaf
2

Para una solución explícita independiente de la zona horaria, use la biblioteca pytz.

import datetime
import pytz

pytz.utc.localize(datetime.datetime(2012,4,1,0,0), is_dst=False).timestamp()

Salida (flotante): 1333238400.0

Moobie
fuente
vi una respuesta similar en stackoverflow.com/a/21145908/4355695 , pero esta como una línea es excelente para mi caso de uso donde los datos entrantes están en UTC y solo .timestamp () asumía que era en hora local .
Nikhil VJ
Esto funciona para fechas inferiores a 1970. Gracias. La respuesta aceptada no funciona para fechas inferiores a 1970. (Python 3.7.3 64-bit Anaconda3)
canbax
-1

En Python 3.7

Devuelve una fecha y hora correspondiente a una cadena de fecha en uno de los formatos emitidos por date.isoformat () y datetime.isoformat (). Específicamente, esta función admite cadenas en los formatos AAAA-MM-DD [* HH [: MM [: SS [.fff [fff]]]] [+ HH: MM [: SS [.ffffff]]]] , donde * puede coincidir con cualquier carácter individual.

https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat

SuperNova
fuente
1
Tenga en cuenta que esto se introdujo en Python 3.7.
keithpjolley