Konwertuj datetime Pythona na epokę za pomocą strftime

209

Mam czas w UTC, od którego chcę liczbę sekund od epoki.

Używam strftime, aby przekonwertować go na liczbę sekund. Biorąc za przykład 1 kwietnia 2012 r.

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

1 kwietnia 2012 UTC z epoki to 1333238400, ale powyższy zwraca 1333234800, który różni się o 1 godzinę.

Wygląda więc na to, że strftime bierze pod uwagę mój czas systemowy i stosuje gdzieś zmianę strefy czasowej. Myślałem, że data i godzina była czysto naiwna?

Jak mogę to obejść? Jeśli to możliwe, unikaj importowania innych bibliotek, chyba że standardowe. (Mam obawy dotyczące przenośności).

kolęda
źródło
11
Czy jestem jedynym, który zauważa, że ​​używasz literałów ósemkowych w liczbach?
Fish Monitor
3
Nowszy Python 3.3+ madatetime.datetime.timestamp(datetime.datetime.utcnow())
MarkHu

Odpowiedzi:

389

Jeśli chcesz przekonwertować datetime Pythona na sekundy od epoki, możesz to zrobić jawnie:

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

W Python 3.3+ możesz timestamp()zamiast tego użyć :

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

Dlaczego nie powinieneś używać datetime.strftime('%s')

Python tak naprawdę nie obsługuje% s jako argumentu dla strftime (jeśli sprawdzisz na http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior nie ma go na liście), jedyne powodem tego jest fakt, że Python przekazuje informacje do strftime systemu, który wykorzystuje lokalną strefę czasową.

>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
Jleahy
źródło
7
Oszalałem próbując dowiedzieć się, dlaczego często widzę strftime („% s”), ale nie ma go w dokumentacji. Dziękuję za nic tego!
Jonathan Vanasco
54
nie używaj .strftime("%s"): nie jest obsługiwany, nie jest przenośny, może dyskretnie wygenerować zły wynik dla świadomego obiektu datetime, nie powiedzie się, jeśli dane wejściowe są w UTC (jak w pytaniu), ale lokalna strefa czasowa nie jest w UTC
jfs
2
@earthmeLon Braketing jest nieprawidłowy. Timedeltas (utworzony przez odjęcie dwóch czasów danych) ma total_seconds, ale czasy danych nie.
jleahy,
2
To nie działa dla mnie:AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'
Michael
3
@ Michael Ta funkcja jest nowa w Pythonie 2.7, musisz używać starszej wersji. W przypadku wersji wcześniejszych niż 2.7 możesz to zrobić td.seconds + td.days*24*3600. To odrzuca część mikrosekund.
jleahy
100

Miałem poważne problemy ze strefami czasowymi i tym podobne. Sposób, w jaki Python radzi sobie z tym wszystkim, jest dość mylący (dla mnie). Wydaje się, że wszystko działa dobrze przy użyciu modułu kalendarza (patrz linki 1 , 2 , 3 i 4 ).

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400
BorrajaX
źródło
7
+1, ponieważ jest to jedyna odpowiedź, która działa na dane wejściowe w pytaniu.
jfs
czy to jest przenośne?
benjaminz
1
Należy to zaznaczyć jako słuszną odpowiedź, ponieważ stanowi to odpowiedź na pytanie, o które chodzi. vnice kudos
Leo Prince
2
To „działa”, ale zwróć uwagę na pytanie: „Mam czas w UTC”. Ta metoda zawsze używa lokalnej strefy czasowej systemu. Nie ma możliwości określenia strefy czasowej. Gdyby aprilFirstw tym przykładzie wystąpiła „świadoma” instancja i używała strefy czasowej innej niż strefa czasowa systemu, wynik nie byłby prawidłowy (strefa czasowa gubi się w timetuple()wywołaniu). Aby uzyskać właściwą odpowiedź na „świadomą” datę, możesz użyć awaredt.timestamp()najnowszego Pythona 3. W Pythonie 2 jest trudniej; Jednym ze sposobów jest użycie arrowbiblioteki. arrow.get(awaredt).timestampzrobię to dobrze.
Adam Williamson
1
Dobra uwaga, @AdamWilliamson, ale kod w tym przykładzie nie lokalizuje datetimeobiektu, więc założyłem, że „mam czas w UTC” oznaczało, że OP miał nieświadomy datetimeobiekt, który, jak zakładano, znajdował się w UTC, dla którego chciał dostać epoch(jeśli datetimezdarzyło się, że był świadomy TZ, to może rzeczywiście zmienić rzeczy). Pamiętaj też, że ta odpowiedź ma prawie 8 lat i od tego czasu wydarzyło się wiele rzeczy ( arrowna przykład została wydana w 2013 r.)
BorrajaX
35
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())
krzyż
źródło
1
jest to niepoprawny sposób pisania time.time()( mktime()może się nie powieść podczas przejścia DST, gdy time.time()nadal działa). I nie odpowiada na pytanie, chyba że lokalna strefa czasowa to UTC (dane wejściowe w pytaniu są w UTC). Nawet jeśli dane wejściowe reprezentowałyby czas lokalny, mktime()mogą również zawieść dla przeszłych / przyszłych dat, jeśli nie będą korzystać z bazy danych tz i jeśli lokalna strefa czasowa może mieć różne przesunięcia utc na przestrzeni lat, np. Europa / Moskwa w latach 2010-2015 - - zamiast tego używaj czasu UTC (jak w pytaniu) lub obiektów daty-godziny obsługujących strefę czasową.
jfs
oto więcej problemów z konwertowaniem czasu lokalnego (np. zwróconego przez .now()) na znacznik czasu epoki (zwrócony przez mktime()) . Jeśli to przeczytasz; rozumiesz, dlaczego dane wejściowe UTC (użyte w pytaniu) są (o wiele) lepsze niż naiwny obiekt datetime reprezentujący czas lokalny
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

(Przepraszam, nie pozwala mi to komentować istniejącej odpowiedzi)

Charles Plager
źródło
Jest tak, ponieważ time.mktime nie uwzględnia części mikrosekundowej, prawda?
Eduardo
1
Poprawny. Struktura krotki czasowej (oparta na strut C) nie ma miejsca na mikrosekundy, więc musimy pobrać informacje z obiektu datetime i dodać je na końcu.
Charles Plager
Na moich komputerach działa to poprawnie, mimo że moją strefą czasową jest ET.
Charles Plager
1
To da ci różne znaczniki czasu w różnych systemach w zależności od lokalnego czasu systemu.
Yousaf
6

jeśli potrzebujesz tylko znacznika czasu w czasie uniksowym / epoki, ta jedna linia działa:

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

i zależy tylko od datetime pracy w python2 i python3

Marc Maxmeister
źródło
2

Działa to w Python 2 i 3:

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

Wystarczy postępować zgodnie z oficjalnymi dokumentami ... https://docs.python.org/2/library/time.html#module-time

Luis Pollo
źródło
1) Zakłada się, że chcesz teraz przekonwertować, a nie losowy obiekt datetime. 2) Nie potrzebujesz kalendarza. time.mktime (randomDateTime.timetuple ()) + randomDateTime.microsecond * 1e-6
Charles Plager
@CharlesPlager time.mktime jest niepoprawny; interpretuje argument w lokalnej strefie czasowej, podczas gdy OP chce czasu interpretowanego w UTC (tak jak robi to kalendarz.timegm).
stewbasic
To jest dla mnie najdokładniejsza odpowiedź, jeśli chcesz przekonwertować swój czas w GMT i chcesz, aby tak było w przypadku konwersji na znacznik czasu epoki.
Yousaf
Wystarczy postępować zgodnie z odpowiedzią, calendar.timegm (datetime.strptime („2019-05-03T05: 40: 09.770494 + 00: 00” [: 16], „% Y-% m-% dT% H:% M”). timetuple ()) Mam znacznik czasu w utc i bez względu na system, na którym działasz, daje mi prawidłowy znacznik czasu, sztuczka polega na użyciu strptime.timetumple
Yousaf
2

Aby uzyskać jednoznaczne rozwiązanie niezależne od strefy czasowej, użyj biblioteki pytz.

import datetime
import pytz

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

Wyjście (liczba zmiennoprzecinkowa): 1333238400.0

Moobie
źródło
widziałem podobną odpowiedź na stackoverflow.com/a/21145908/4355695 , ale ten jako jedno-liniowy jest świetny w moim przypadku użycia, w którym przychodzące dane są w UTC, a tylko .timestamp () zakładał, że jest to czas lokalny .
Nikhil VJ
Działa to dla dat mniejszych niż 1970. Dziękuję. Przyjęta odpowiedź nie działa dla dat krótszych niż 1970. (Python 3.7.3 64-bit Anaconda3)
canbax
-1

W Pythonie 3.7

Zwraca datę i godzinę odpowiadającą łańcuchowi daty w jednym z formatów emitowanych przez date.isoformat () i datetime.isoformat (). W szczególności ta funkcja obsługuje ciągi w formacie (-ach) RRRR-MM-DD [* HH [: MM [: SS [.fff [fff]]]] [+ HH: MM [: SS [.ffffff]]]] , gdzie * może pasować do dowolnego pojedynczego znaku.

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

SuperNova
źródło
1
Pamiętaj, że zostało to wprowadzone w Pythonie 3.7.
keithpjolley