Convierta datetime a la marca de tiempo Unix y conviértalo de nuevo en Python

Tengo dt = datetime(2013,9,1,11) , y me gustaría obtener una marca de tiempo Unix de este objeto datetime.

Cuando hago dt - datetime(1970,1,1)).total_seconds() 1378033200 la marca de tiempo 1378033200 .

Al volver a convertirlo usando datetime.fromtimestamp obtuve datetime.datetime(2013, 9, 1, 6, 0) .

La hora no coincide. ¿Qué extrañé aquí?

Lo que te perdiste aquí es zonas horarias.

Presumiblemente tienes cinco horas fuera de la UTC, así que 2013-09-01T11: 00: 00 local y 2013-09-01T06: 00: 00Z son el mismo horario.

Debe leer la parte superior de los documentos de datetime , que explican las zonas horarias y los objetos “ingenuos” y “conscientes”.

Si su fecha y hora original fue UTC, la forma de recuperarla es usar utcfromtimestamp lugar de fromtimestamp .

Por otra parte, si su fecha y hora original original era local, no debería haberle restado una marca de tiempo UTC en primer lugar; use datetime.fromtimestamp(0) lugar.

O, si tenía un objeto de fecha y hora consciente, necesita usar una época local (consciente) en ambos lados, o convertir explícitamente desde y hacia UTC.

Si tiene, o puede actualizarse a, Python 3.3 o posterior, puede evitar todos estos problemas con solo usar el método de timestamp lugar de tratar de descubrir cómo hacerlo usted mismo. E incluso si no lo hace, puede considerar pedir prestado su código fuente .

(Y si puedes esperar a Python 3.4, parece que es probable que PEP 341 llegue a la versión final, lo que significa que todas las cosas de las que JF Sebastian y yo estuvimos hablando en los comentarios deberían ser posibles con solo la stdlib, y trabajando de la misma manera tanto en Unix como en Windows.)

la solución es

 import time import datetime d = datetime.date(2015,1,5) unixtime = time.mktime(d.timetuple()) 

En lugar de esta expresión para crear una marca de tiempo POSIX a partir de dt ,

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

Utilizar esta:

 int(dt.strftime("%s")) 

Obtengo la respuesta correcta en tu ejemplo usando el segundo método.

EDIT: Algunos seguimiento … Después de algunos comentarios (ver más abajo), tenía curiosidad acerca de la falta de soporte o documentación para %s en strftime . Esto es lo que encontré:

En la fuente de Python para datetime y time , la cadena STRFTIME_FORMAT_CODES nos dice:

 "Other codes may be available on your platform. See documentation for the C library strftime function." 

Así que ahora, si contamos con man strftime (en sistemas BSD como Mac OS X), encontrará soporte para %s :

 "%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))." 

De todos modos, es por eso que %s funciona en los sistemas que hace. Pero hay mejores soluciones para el problema de OP (que tienen en cuenta las zonas horarias). Vea la respuesta aceptada de @abarnert aquí.

Si desea convertir un datetime de python a segundos desde la época, debe hacerlo explícitamente:

 >>> import datetime >>> datetime.datetime(2012,04,01,0,0).strftime('%s') '1333234800' >>> (datetime.datetime(2012,04,01,0,0) - datetime.datetime(1970,1,1)).total_seconds() 1333238400.0 

En Python 3.3+ puedes usar timestamp() lugar:

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

Si su objeto datetime representa la hora UTC, no use time.mktime, ya que se supone que la tupla está en su zona horaria local. En su lugar, use calendar.timegm:

 >>> import datetime, calendar >>> d = datetime.datetime(1970, 1, 1, 0, 1, 0) >>> calendar.timegm(d.timetuple()) 60 

Para trabajar con zonas horarias UTC:

 time_stamp = calendar.timegm(dt.timetuple()) datetime.utcfromtimestamp(time_stamp) 

Bueno, al convertir la marca de tiempo de UN unix, python básicamente asume UTC, pero al volver a convertir, te dará una fecha convertida a tu zona horaria local.

Vea esta pregunta / respuesta; Obtener la zona horaria utilizada por datetime.datetime.fromtimestamp ()

Has perdido la información de la zona horaria (ya contestada, de acuerdo)

arrow paquete de arrow permite evitar esta tortura con tiempos de datos; Ya está escrito, probado, pypi-publicado, cross-python (2.6 – 3.xx).

Todo lo que necesita: pip install arrow (o agregar a dependencias)

Solución para tu caso

 dt = datetime(2013,9,1,11) arrow.get(dt).timestamp # >>> 1378033200 bc = arrow.get(1378033200).datetime print(bc) # >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc()) print(bc.isoformat()) # >>> '2013-09-01T11:00:00+00:00' 
 def dt2ts(dt, utc=False): if utc: return calendar.timegm(dt.timetuple()) if dt.tzinfo is None: return int(time.mktime(dt.timetuple())) utc_dt = dt.astimezone(tz.tzutc()).timetuple() return calendar.timegm(utc_dt) 

Si desea la marca de tiempo UTC: time.mktime solo para dt local. Use calendar.timegm es seguro pero debe la zona utc, por lo tanto, cambie la zona a utc. Si dt ​​en UTC solo usa calendar.timegm .