Convertir python datetime en epoch avec strftime

210

J'ai un temps en UTC à partir duquel je veux le nombre de secondes depuis l'époque.

J'utilise strftime pour le convertir en nombre de secondes. Prenons le 1er avril 2012 comme exemple.

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

Le 1er avril 2012, l'UTC de l'époque est 1333238400, mais ce qui précède renvoie 1333234800, ce qui est différent d'une heure.

Il semble donc que le strftime prenne en compte l'heure de mon système et applique un décalage de fuseau horaire quelque part. Je pensais que datetime était purement naïf?

Comment contourner cela? Si possible en évitant d'importer d'autres bibliothèques sauf standard. (J'ai des problèmes de portabilité).

Noel
la source
11
Suis-je le seul à noter que vous utilisez des littéraux octaux dans les nombres?
Fish Monitor
problème Python
jfs
3
Le plus récent Python 3.3+ adatetime.datetime.timestamp(datetime.datetime.utcnow())
MarkHu

Réponses:

391

Si vous voulez convertir un datetime python en secondes depuis epoch, vous pouvez le faire explicitement:

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

Dans Python 3.3+, vous pouvez utiliser à la timestamp()place:

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

Pourquoi vous ne devriez pas utiliser datetime.strftime('%s')

Python ne prend pas réellement en charge% s comme argument de strftime (si vous vérifiez sur http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior ce n'est pas dans la liste), le seul la raison pour laquelle cela fonctionne est parce que Python transmet les informations au strftime de votre système, qui utilise votre fuseau horaire local.

>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
jleahy
la source
7
Je suis devenu fou en essayant de comprendre pourquoi je vois beaucoup de strftime ("% s"), mais ce n'est pas dans les documents. Merci pour rien ça!
Jonathan Vanasco
54
ne pas utiliser .strftime("%s"): il n'est pas pris en charge, il n'est pas portable, il peut produire silencieusement un mauvais résultat pour un objet datetime conscient, il échoue si l'entrée est en UTC (comme dans la question) mais le fuseau horaire local n'est pas UTC
jfs
2
@earthmeLon Votre bracketing est incorrect. Les timedeltas (obtenus en soustrayant deux datetimes) ont total_seconds, mais pas les datetimes.
jleahy
2
Cela ne fonctionne pas pour moi:AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'
Michael
3
@Michael Cette fonction est nouvelle dans Python 2.7, vous devez utiliser une ancienne version. Pour les versions antérieures à 2.7, vous pouvez le faire td.seconds + td.days*24*3600. Cela supprime la partie microsecondes.
jleahy
100

J'ai eu de sérieux problèmes avec les fuseaux horaires et autres. La façon dont Python gère tout cela est assez déroutante (pour moi). Les choses semblent bien fonctionner avec le module calendrier (voir liens 1 , 2 , 3 et 4 ).

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400
BorrajaX
la source
7
+1 car c'est la seule réponse qui fonctionne pour l'entrée dans la question.
jfs
est-ce portable?
benjaminz
1
Cela devrait être marqué comme la réponse légitime, car cela répond à la préoccupation en question. vnice kudos
Leo Prince
2
Cela «fonctionne», mais notez la question posée: «J'ai un temps en UTC» Cette méthode utilisera toujours le fuseau horaire local du système. Il n'y a aucun moyen de spécifier un fuseau horaire. Si, aprilFirstdans cet exemple, il s'agissait d'une instance «consciente» et utilisait un fuseau horaire différent du fuseau horaire du système, le résultat ne serait pas correct (le fuseau horaire est perdu lors de l' timetuple()appel). Pour obtenir la bonne réponse pour un datetime «conscient», vous pouvez utiliser awaredt.timestamp()sur Python 3 récent. Pour Python 2, c'est plus difficile; une façon consiste à utiliser la arrowbibliothèque. arrow.get(awaredt).timestample fera bien.
Adam Williamson
1
Bon point, @AdamWilliamson, mais le code dans l'exemple ne localise pas l' datetimeobjet, j'ai donc supposé que le "J'ai un temps en UTC" signifiait que l'OP avait un datetimeobjet ignorant qui était supposé être en UTC pour lequel il voulait pour en obtenir un epoch(s'il datetimes'avérait être conscient de TZ, cela pourrait en effet changer les choses). Aussi, gardez à l'esprit que cette réponse a presque 8 ans et que beaucoup de choses se sont produites depuis ( arrowsortie en 2013, par exemple)
BorrajaX
35
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())
srossross
la source
1
il s'agit d'une façon incorrecte d'écrire time.time()( mktime()peut échouer pendant les transitions DST tout en time.time()continuant à fonctionner). Et il ne répond à la question que si le fuseau horaire local est UTC (l'entrée dans la question est en UTC). Même si l'entrée représente une heure locale, elle mktime()peut également échouer pour les dates passées / futures si elle n'utilise pas la base de données tz et si le fuseau horaire local peut avoir différents décalages utc au fil des ans, par exemple Europe / Moscou en 2010-2015 - - utilisez plutôt des heures UTC (comme dans la question) ou des objets datetime compatibles avec le fuseau horaire.
jfs
voici plus de problèmes avec la conversion d'une heure locale (telle que retournée par .now()) en horodatage d'époque (retournée par mktime()) . Si vous le lisez; vous comprenez pourquoi l'entrée UTC (utilisée dans la question) est (beaucoup) plus préférable qu'un objet datetime naïf représentant l'heure locale
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

(Désolé, cela ne m'a pas permis de commenter la réponse existante)

Charles Plager
la source
C'est parce que time.mktime ne prend pas en compte la partie microseconde, non?
Eduardo
1
Correct. La structure de tuple temporel (basée sur C strut) n'a pas d'espace pour les microsecondes, nous devons donc récupérer les informations de l'objet datetime et les ajouter à la fin.
Charles Plager
Sur mes machines, cela fonctionne correctement même si mon fuseau horaire est ET.
Charles Plager
1
Cela vous donnera différents horodatages sur différents systèmes en fonction de l'heure locale du système.
Yousaf
6

si vous avez juste besoin d'un horodatage en temps unix / epoch, cette ligne fonctionne:

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

et ne dépend que des datetime travaux en python2 et python3

Marc Maxmeister
la source
3

Cela fonctionne en Python 2 et 3:

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

Juste en suivant les documents officiels ... https://docs.python.org/2/library/time.html#module-time

Luis Pollo
la source
1) Cela suppose que vous souhaitez convertir maintenant, pas un objet datetime aléatoire. 2) Vous n'avez pas besoin de calendrier. time.mktime (randomDateTime.timetuple ()) + randomDateTime.microsecond * 1e-6
Charles Plager
@CharlesPlager time.mktime est incorrect; il interprète l'argument dans le fuseau horaire local, tandis que l'OP souhaite que l'heure soit interprétée en UTC (comme le fait calendar.timegm).
stewbasic
C'est la réponse la plus précise pour moi, si vous cherchez à convertir votre temps en GMT et que vous souhaitez que cela reste ainsi lors de la conversion en horodatage d'époque.
Yousaf
Juste après votre réponse, calendar.timegm (datetime.strptime ("2019-05-03T05: 40: 09.770494 + 00: 00" [: 16], '% Y-% m-% dT% H:% M'). timesuple ()) J'ai un horodatage dans utc et quel que soit le système sur lequel vous l'exécutez, il me donne un horodatage correct, l'astuce consiste à utiliser strptime.timetumple
Yousaf
2

Pour une solution explicite indépendante du fuseau horaire, utilisez la bibliothèque pytz.

import datetime
import pytz

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

Sortie (float): 1333238400.0

Moobie
la source
a vu une réponse similaire sur stackoverflow.com/a/21145908/4355695 , mais celle-ci en tant que ligne unique est idéale pour mon cas d'utilisation où les données entrantes sont en UTC et juste .timestamp () supposait qu'elles étaient en heure locale .
Nikhil VJ
Cela fonctionne pour des dates inférieures à 1970. Merci. La réponse acceptée ne fonctionne pas pour les dates inférieures à 1970. (Python 3.7.3 Anaconda3 64 bits)
canbax
-1

En Python 3.7

Renvoie un datetime correspondant à une date_string dans l'un des formats émis par date.isoformat () et datetime.isoformat (). Plus précisément, cette fonction prend en charge les chaînes au format AAAA-MM-JJ [* HH [: MM [: SS [.fff [fff]]]] [+ HH: MM [: SS [.ffffff]]]]] , où * peut correspondre à n'importe quel caractère.

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

SuperNova
la source
1
Sachez que cela a été introduit dans Python 3.7.
keithpjolley