¿Cómo puedo convertir un objeto datetime a milisegundos desde epoch (tiempo unix) en Python?

356

Tengo un datetimeobjeto Python que quiero convertir a tiempo unix, o segundos / milisegundos desde la época de 1970.

¿Cómo hago esto?

SuperString
fuente
Si aterrizaste aquí solo queriendo segundos de época actuales con precisión de milisegundos, prueba $ python -c 'import time; print(time.time())'cuál dio:1584487455.698623
MarkHu

Respuestas:

473

Me parece que la forma más sencilla de hacer esto es

import datetime

epoch = datetime.datetime.utcfromtimestamp(0)

def unix_time_millis(dt):
    return (dt - epoch).total_seconds() * 1000.0
Sophie Alpert
fuente
32
Hasta ahora, esta es la mejor solución (si la versión de Python> 2.7). ¡Porque la implementación de %sdepende del sistema operativo! Por lo tanto, cualquiera que quiera que el código funcione de manera confiable, independientemente de qué sistema operativo, NUNCA debe usar %s. Para 2.3 <py ver <2.7. Simplemente se puede construir un total_seconds()como este:delta.days*86400+delta.seconds+delta.microseconds/1e6
Wang
14
nota: dtdebe estar en UTC (no local). Vea una respuesta similar con el soporte de Python 2.6 / 3
jfs
77
Vale la pena mencionar que si todo lo que quiere es una verdadera marca de tiempo de Unix como se define aquí en.wikipedia.org/wiki/Unix_time (y solo usará la función unix_time de esta respuesta), entonces debe ajustar delta.total_seconds () con int a evite terminar con un flotador
corford
1
la época calculada usando utcfromtimestamp(0)puede causar un desplazamiento 'tz' solo si 'tz' no es 0. Esto se debe a que dt en dt- epoch'tz' se ha calculado en él, ya que la época es el tiempo UTC. La mejor manera de calcular la época es epoch = datetime.datetime(1970, 1, 1)donde se considera la zona horaria.
ahj
35
¿Por qué oh por qué datetime.utcfromtimestamp(0)devuelve una fecha y hora sin tzinfo? Está justo ahí en el nombre del método, utc fromtimestamp. Para que no sea ingenuo, tengo que hacer algo así datetime.utcfromtimestamp(0).replace(tzinfo=pytz.UTC). Esto es necesario si dtconoce la zona horaria o de lo contrario obtendráTypeError: can't subtract offset-naive and offset-aware datetimes
FGreg
171

En Python 3.3, se agregó un nuevo método timestamp:

import datetime
seconds_since_epoch = datetime.datetime.now().timestamp()

Su pregunta decía que necesitaba milisegundos, que puede obtener así:

milliseconds_since_epoch = datetime.datetime.now().timestamp() * 1000

Si lo usa timestampen un objeto de fecha y hora ingenuo, se supone que está en la zona horaria local. Utilice objetos de fecha y hora con reconocimiento de zona horaria si esto no es lo que pretende que suceda.

eshizhan
fuente
28
Nota: el .timestamp()método supone que una fecha y hora de entrada ingenua se encuentra en la zona horaria local (y la hora local puede ser ambigua). Si está en UTC, use dt.replace(tzinfo=timezone.utc).timestamp()en su lugar .
jfs
11
datetime.timestamp () devuelve epoch segundos como flotante. Para obtener milisegundos: int (datetime.timestamp () * 1000)
Solar.gy
99
Esta respuesta no es un ejemplo de copiar y pegar, en el espíritu de los documentos no amigables con los humanos en docs.python.org/3/library/… --esto es: datetime.datetime.timestamp(datetime.datetime.now())
MarkHu
3
En 3.6 (al menos), datetime.timestamp () supone que una zona horaria ingenua (tzinfo = None) datetime está en UTC. Por lo tanto, siempre es mejor configurar su zona horaria: datetime.datetime.now(pytz.timezone('Europe/Paris')).timestamp() == datetime.datetime.now(pytz.utc).timestamp() == datetime.datetime.utcnow().timestamp()pero no (siempre) igual a datetime.datetime.now().timestamp()(este último solo es igual al resto si el tz local es UTC ...)
Bluu
1
Para su interés, el reverso es] fromtimestamp( docs.python.org/3/library/… )
Flimm
98
>>> import datetime
>>> # replace datetime.datetime.now() with your datetime object
>>> int(datetime.datetime.now().strftime("%s")) * 1000 
1312908481000

O la ayuda del módulo de tiempo (y sin formato de fecha):

>>> import datetime, time
>>> # replace datetime.datetime.now() with your datetime object
>>> time.mktime(datetime.datetime.now().timetuple()) * 1000
1312908681000.0

Respondido con ayuda de: http://pleac.sourceforge.net/pleac_python/datesandtimes.html

Documentación:

miku
fuente
66
Por cierto, strftime ("% s") me devuelve una cadena vacía. La segunda forma funciona bien.
Pavel Vlasov
23
Solo tiene una segunda precisión
shuckc
66
'% s' no es compatible con Python, por ejemplo, podría estar ausente en Windows. .timetuple()devuelve tm_isdst=-1obliga mktime()a adivinar. Puede adivinar erróneamente durante el horario de verano (50% de probabilidad de un error +/- hora). Ambos '% s' y mktime()pueden usar el desplazamiento utc incorrecto para fechas del pasado. Necesita una base de datos histórica db como la proporcionada por el pytzmódulo para convertir de manera confiable la hora local a la marca de tiempo POSIX (a menos que el sistema operativo ya proporcione dicha base de datos)
jfs
1
time.mktime(ts.timetuple())donde ts es el objeto de fecha y hora de python
suhailvs
1
@suhail: lee mi comentario anterior sobre mktime/timetuple. También timetuple()elimina fracciones de segundo y el punto de la pregunta es obtener la marca de tiempo con una precisión de milisegundos.
jfs
13

Así es como lo hago:

from datetime import datetime
from time import mktime

dt = datetime.now()
sec_since_epoch = mktime(dt.timetuple()) + dt.microsecond/1000000.0

millis_since_epoch = sec_since_epoch * 1000
estani
fuente
2
@JFSebastian ¡Gracias por el aviso! de hecho no se está considerando dst. Si su servidor está en tiempo local en lugar de UTC, entonces hará la diferencia. No he encontrado (todavía) ninguna razón convincente para configurar servidores en otra cosa que no sea UTC. Mi moto es "escribe UTC, lee la hora local" para que sepas siempre dónde te
hospedas
2
Siempre puede usar calendar.timegm en lugar de mktime para evitar el problema de que mktime intente adivinar la zona horaria.
Decko
13

Recomendaciones de los documentos de Python 2.7 para el timemódulo

Convertir entre representaciones de tiempo

Ankur Agarwal
fuente
@ChristopherBull Solo divide el número de milisegundos por 1000 para llegar a segundos
Jonas
55
Usted entendió mal y lo entendió al revés. Los segundos están disponibles en las funciones anteriores. Puede convertirlo a milisegundos, pero sería la precisión de un segundo.
Christopher Bull
1
Esta respuesta usa el timemódulo, pero el OP preguntó sobre el datetimemódulo. FWIW, la época actual más simple esint(time.time())
MarkHu
7
from datetime import datetime
from calendar import timegm

# Note: if you pass in a naive dttm object it's assumed to already be in UTC
def unix_time(dttm=None):
    if dttm is None:
       dttm = datetime.utcnow()

    return timegm(dttm.utctimetuple())

print "Unix time now: %d" % unix_time()
print "Unix timestamp from an existing dttm: %d" % unix_time(datetime(2014, 12, 30, 12, 0))
Corford
fuente
timegm()funciona solo con tiempo utc. No usa, tm_isdstpor lo tanto, podría usar en utcnow.timetuple()lugar de utcnow.utctimetuple(). Nota: usar naive_local_datetime.utctimetuple()estaría mal aquí. No traduce la hora local a utc. También timetuple()llame a las fracciones de tiras de un segundo del resultado (si importa depende de la aplicación). También la pregunta se refiere a * milli * segundos, no segundos
jfs
Prefiero usar utcnow () y utctimetuple () para dejar el código absolutamente claro de que estás tratando con UTC (y de esta manera cualquiera que lo lea no tiene que recordar que timegm es solo UTC). utctimetuple () no implica traducción en un objeto dttm ingenuo (por lo tanto, al iniciar el dttm con utcnow ()). Además, la pregunta mencionó segundos o milisegundos.
Corford
Nota: debería haber dicho en el último comentario que leí la pregunta que implica que quería segundos o milisegundos (probablemente mi error). Para los millis, simplemente multiplique por 1000 (como sugiere la respuesta de mayor puntaje).
Corford
utctimetuple()tiras de fracciones de segundo. Multiplicar por 1000no los recuperará.
jfs
1
Debido a la forma en que el OP hizo esta pregunta, no está claro exactamente qué es lo que él / ella quería (es decir, una verdadera marca de tiempo de Unix o una marca de tiempo con una precisión de milisegundos). Independientemente, ambas preguntas ya han sido formuladas y respondidas en otros lugares. Habiendo dicho eso, creo que las respuestas aquí son las más rápidas y limpias para que la gente asimile y haga un buen trabajo al ilustrar las diversas soluciones al problema.
corford
3
>>> import datetime
>>> import time
>>> import calendar

>>> #your datetime object
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2013, 3, 19, 13, 0, 9, 351812)

>>> #use datetime module's timetuple method to get a `time.struct_time` object.[1]
>>> tt = datetime.datetime.timetuple(now)
>>> tt
time.struct_time(tm_year=2013, tm_mon=3, tm_mday=19, tm_hour=13, tm_min=0, tm_sec=9,     tm_wday=1, tm_yday=78, tm_isdst=-1)

>>> #If your datetime object is in utc you do this way. [2](see the first table on docs)
>>> sec_epoch_utc = calendar.timegm(tt) * 1000
>>> sec_epoch_utc
1363698009

>>> #If your datetime object is in local timeformat you do this way
>>> sec_epoch_loc = time.mktime(tt) * 1000
>>> sec_epoch_loc
1363678209.0

[1] http://docs.python.org/2/library/datetime.html#datetime.date.timetuple

[2] http://docs.python.org/2/library/time.html

Jinesh
fuente
3

Aquí hay otra forma de solución con la normalización de su objeto de tiempo:

def to_unix_time(timestamp):
    epoch = datetime.datetime.utcfromtimestamp(0) # start of epoch time
    my_time = datetime.datetime.strptime(timestamp, "%Y/%m/%d %H:%M:%S.%f") # plugin your time object
    delta = my_time - epoch
    return delta.total_seconds() * 1000.0
pieles
fuente
2

Un poco de código de pandas:

import pandas

def to_millis(dt):
    return int(pandas.to_datetime(dt).value / 1000000)
volhv
fuente
1
import time
seconds_since_epoch = time.mktime(your_datetime.timetuple()) * 1000
MattoTodd
fuente
99
¡Esto está mal! El timetuple no incluye milisegundos, por lo tanto, mktime no devolverá la época con una resolución de milisegundos. Es inútil en este caso.
Wang
@Wang: tiene razón señor, esto no devuelve millis, solo segundos
MattoTodd
1
Sin * 1000embargo, si eliminas , obtienes seconds_since_epoch. Votar esta respuesta porque no me importan los milisegundos en este momento.
Michael Scheper
0

Aquí hay una función que hice basada en la respuesta anterior

def getDateToEpoch(myDateTime):
    res = (datetime.datetime(myDateTime.year,myDateTime.month,myDateTime.day,myDateTime.hour,myDateTime.minute,myDateTime.second) - datetime.datetime(1970,1,1)).total_seconds()
    return res

Puede ajustar el valor devuelto de esta manera: str (int (res)) Para devolverlo sin un valor decimal para usarlo como cadena o simplemente int (sin el str)

Gil Allen
fuente
-14

Esta otra solución para datetime encubierto a unixtimestampmillis.

private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    public static long GetCurrentUnixTimestampMillis()
    {
        DateTime localDateTime, univDateTime;
        localDateTime = DateTime.Now;          
        univDateTime = localDateTime.ToUniversalTime();
        return (long)(univDateTime - UnixEpoch).TotalMilliseconds;
    } 
samsanthosh2008
fuente
2
La pregunta es sobre el lenguaje Python
Stéphane