Преобразование даты и времени Python в эпоху с помощью strftime

210

У меня есть время в UTC, с которого я хочу количество секунд с начала эпохи.

Я использую strftime, чтобы преобразовать его в количество секунд. Принимая 1 апреля 2012 года в качестве примера.

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

1 апреля 2012 года UTC от эпохи - 1333238400, но это выше возвращает 1333234800, который отличается на 1 час.

Похоже, что strftime учитывает мое системное время и где-то применяет сдвиг часовых поясов. Я думал, что свидание было чисто наивным?

Как я могу обойти это? По возможности избегать импорта других библиотек, кроме стандартных. (У меня есть проблемы с переносимостью).

Ноэль
источник
11
Я единственный, кто заметил, что вы используете восьмеричные литералы в числах?
Fish Monitor
3
Более новый Python 3.3+ имеетdatetime.datetime.timestamp(datetime.datetime.utcnow())
MarkHu

Ответы:

391

Если вы хотите преобразовать дату и время Python в секунды с начала эпохи, вы можете сделать это явно:

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

В Python 3.3+ вы можете использовать timestamp()вместо:

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

Почему вы не должны использовать datetime.strftime('%s')

Python на самом деле не поддерживает% s в качестве аргумента для strftime (если вы проверите по адресу http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior, его нет в списке), единственный причина в том, что он работает, потому что Python передает информацию в strftime вашей системы, которая использует ваш местный часовой пояс.

>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
jleahy
источник
7
Я схожу с ума, пытаясь понять, почему я часто вижу strftime ("% s"), но его нет в документации. Спасибо тебе за это!
Джонатан Ванаско
54
не используйте .strftime("%s"): он не поддерживается, он не переносим, ​​он может молча выдавать неправильный результат для осведомленного объекта даты и времени, он терпит неудачу, если ввод находится в формате UTC (как в вопросе), но локальный часовой пояс не является UTC
jfs
2
@earthmeLon Ваш брекет неправильный. Timedeltas (сделанные путем вычитания двух datetime) имеют total_seconds, а datetime - нет.
Джели
2
Это не работает для меня:AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'
Майкл
3
@Michael Эта функция является новой в Python 2.7, вы должны использовать более старую версию. Для версий до 2.7 вы можете сделать td.seconds + td.days*24*3600. Это отбрасывает часть микросекунд.
Jleahy
100

У меня были серьезные проблемы с часовыми поясами и тому подобное. То, как Python обрабатывает все, что случается, довольно запутанно (для меня). С модулем календаря все работает нормально (см. Ссылки 1 , 2 , 3 и 4 ).

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400
BorrajaX
источник
7
+1, потому что это единственный ответ, который работает для ввода в вопросе.
JFS
это портативный?
Бенджаминз
1
Это должно быть помечено как правильный ответ, так как это отвечает рассматриваемой проблеме. vnice kudos
Лев Принц
2
Это «работает», но обратите внимание на вопрос: «У меня есть время в UTC». Этот метод всегда использует локальный часовой пояс системы. Нет способа указать часовой пояс. Если бы aprilFirstв этом примере был экземпляр «в курсе» и использовался часовой пояс, отличный от часового пояса системы, результат был бы неправильным (часовой пояс теряется при timetuple()вызове). Чтобы получить правильный ответ для «осведомленной» даты и времени, которую вы можете использовать awaredt.timestamp()в недавнем Python 3. Для Python 2 это сложнее; Одним из способов является использование arrowбиблиотеки. arrow.get(awaredt).timestampпоймет это правильно.
Адам Уильямсон
1
Хороший вопрос, @AdamWilliamson, но код в примере не локализует datetimeобъект, поэтому я предположил, что «у меня есть время в UTC» означало, что у OP был незнакомый datetimeобъект, который, как предполагалось, был в UTC, для которого он хотел чтобы получить epoch(если datetimeслучилось, что TZ-осведомленный, это, действительно, могло бы изменить вещи). Кроме того, имейте в виду, что этому ответу уже почти 8 лет, и с тех пор произошло много событий (например, arrowбыл выпущен в 2013 году)
BorrajaX
35
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())
srossross
источник
1
это неправильный способ записи time.time()( mktime()может произойти сбой во время перехода на летнее время, пока он time.time()продолжает работать). И это не отвечает на вопрос, если местный часовой пояс не UTC (ввод в вопросе в UTC). Даже если ввод будет представлять местное время, он mktime()может также потерпеть неудачу для прошлых / будущих дат, если он не использует базу данных tz и если местный часовой пояс может иметь различные смещения utc в течение многих лет, например, Европа / Москва в 2010-2015 гг. - - вместо этого используйте время UTC (как в вопросе) или объекты datetime с учетом часового пояса.
Jfs
здесь больше проблем с преобразованием местного времени (например, возвращенного .now()) в метку времени эпохи (возвращенного mktime()) . Если вы читаете это; Вы понимаете, почему ввод UTC (используемый в вопросе) (намного) предпочтительнее, чем наивный объект даты и времени, представляющий местное время
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

(Извините, это не позволило бы мне прокомментировать существующий ответ)

Чарльз Плагер
источник
Это потому, что time.mktime не учитывает микросекундную часть, верно?
Эдуардо
1
Верный. Структура кортежа времени (основанная на C-strut) не имеет места для микросекунд, поэтому нам нужно извлечь информацию из объекта datetime и добавить ее в конце.
Чарльз Плагер
На моих машинах это работает правильно, хотя мой часовой пояс ET.
Чарльз Плагер
1
Это даст вам разные временные метки в разных системах в зависимости от местного времени системы.
Юсаф
6

если вам просто нужна временная метка в Unix / Epoch Time, эта строка работает:

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

и зависит только от datetime работ в python2 и python3

Марк Максмейстер
источник
3

Это работает в Python 2 и 3:

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

Просто следуйте официальным документам ... https://docs.python.org/2/library/time.html#module-time

Луис Полло
источник
1) Предполагается, что вы хотите преобразовать сейчас, а не случайный объект даты и времени. 2) Вам не нужен календарь. time.mktime (randomDateTime.timetuple ()) + randomDateTime.microsecond * 1e-6
Чарльз Плагер
@CharlesPlager time.mktime неверен; он интерпретирует аргумент в местном часовом поясе, тогда как OP хочет, чтобы время интерпретировалось в UTC (как calendar.timegm).
тушеное мясо
Это самый точный ответ для меня, если вы хотите конвертировать свое время в GMT и хотите, чтобы оно сохранялось при преобразовании в метку времени эпохи.
Юсаф
Сразу после вашего ответа calendar.timegm (datetime.strptime ("2019-05-03T05: 40: 09.770494 + 00: 00" [: 16], «% Y-% m-% dT% H:% M»). timetuple ()) У меня есть метка времени в utc, и независимо от того, на какой системе вы работаете, она дает правильную метку времени, трюк в том, чтобы использовать strptime.timetumple
Yousaf
2

Для явного решения, не зависящего от часового пояса, используйте библиотеку pytz.

import datetime
import pytz

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

Выход (float): 1333238400.0

Moobie
источник
видел аналогичный ответ на stackoverflow.com/a/21145908/4355695 , но этот, как однострочный, отлично подходит для моего случая использования, когда входящие данные находятся в UTC, и просто .timestamp () предполагал, что они находятся по местному времени ,
Nikhil VJ
Это работает для дат менее 1970 года. Спасибо. Принятый ответ не работает для дат менее 1970. (Python 3.7.3 64-битная Anaconda3)
canbax
-1

В Python 3.7

Возвращает datetime, соответствующий строке date_string в одном из форматов, испускаемых date.isoformat () и datetime.isoformat (). В частности, эта функция поддерживает строки в формате (форматах) ГГГГ-ММ-ДД [* ЧЧ [: ММ [: СС [.fff [fff]]]] [+ ЧЧ: ММ [: СС [.ffffff]]]] где * может соответствовать любой отдельный символ.

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

SuperNova
источник
1
Имейте в виду, что это было введено в Python 3.7.
Keithpjolley