В Python, как вы конвертируете объект `datetime` в секунды?

226

Извиняюсь за простой вопрос ... Я новичок в Python ... Я искал вокруг, и, кажется, ничего не работает.

У меня есть куча объектов datetime, и я хочу рассчитать количество секунд с фиксированного времени в прошлом для каждого из них (например, с 1 января 1970 года).

import datetime
t = datetime.datetime(2009, 10, 21, 0, 0)

Кажется, это только различие между датами, у которых есть разные дни:

t.toordinal()

Любая помощь очень ценится.

Натан Липпи
источник
2
Я бы, вероятно, преобразовал оба в S начиная с эпохи и пошел бы оттуда: int(t.timestamp())
nerdwaller
для противоположной операции перейдите сюда: конвертировать секунды-с-эпохи в объект-дату-время
Тревор Бойд Смит

Ответы:

233

Для особой даты 1 января 1970 года есть несколько вариантов.

Для любой другой даты начала вам нужно получить разницу между двумя датами в секундах. Вычитание двух дат дает timedeltaобъект, который с Python 2.7 имеет total_seconds()функцию.

>>> (t-datetime.datetime(1970,1,1)).total_seconds()
1256083200.0

Дата начала обычно указывается в UTC, поэтому для получения правильных результатов datetimeвы должны указать эту формулу в UTC. Если вы datetimeеще не в UTC, вам необходимо преобразовать его перед использованием или прикрепить tzinfoкласс с соответствующим смещением.

Как отмечено в комментариях, если у вас есть tzinfoприкрепленное к вашему, datetimeто оно вам понадобится и на дату начала, иначе вычитание не удастся; для приведенного выше примера я бы добавил, tzinfo=pytz.utcесли вы используете Python 2 или tzinfo=timezone.utcPython 3.

Марк Рэнсом
источник
1
Теперь Python предупреждает меня: «Ошибка TypeError: невозможно вычесть смещенные наивные и учитывающие смещение даты и времени» Какое наилучшее решение можно исправить?
Аарон Эш
2
@Charybdis, попробуй datetime.datetime(1970,1,1,tzinfo=pytz.utc).
Марк Рэнсом
9
Подумайте об использовании: datetime.datetime.utcfromtimestamp(0) я использовал это, чтобы легко получить «эпоху». Обратите внимание, что эпоха не всегда одинакова на всех системах.
DA
3
Будьте очень осторожны с часовыми поясами здесь. Я на UTC + 2, что означает, что на выходе time.time()и datetime.now() - datetime(1970, 1, 1)отличаются на 7200 секунд. Скорее используйте (t - datetime.datetime.fromtimestamp(0)).total_seconds(). Вы не использовать , utcfromtimestamp(0)если вы хотите , чтобы преобразовать DateTime в локальном часовом поясе.
Карл
2
@DA: Python не поддерживает эпохи, отличные от POSIX . Все системы, в которых работает Python, используют одну и ту же эпоху: 1970-01-01 00:00:00 UTC
jfs
130

Чтобы узнать время Unix (секунды с 1 января 1970 года):

>>> import datetime, time
>>> t = datetime.datetime(2011, 10, 21, 0, 0)
>>> time.mktime(t.timetuple())
1319148000.0
Марк Байерс
источник
22
будьте осторожны при использовании time.mktime, поскольку он выражает местное время и зависит от платформы
Shih-Wen Su
7
Будьте осторожны. Это укусило меня за задницу
Arg
Предполагается, что tэто местное время. Смещение UTC для местного часового пояса в прошлом могло быть другим, и если mktime()(библиотека C) не имеет доступа к историческим данным часового пояса на данной платформе, это может привести к сбою ( pytzэто переносной способ доступа к базе данных tz). Кроме того, местное время может быть неоднозначным, например, во время переходов DST - вам нужна дополнительная информация для устранения неоднозначности, например, если вы знаете, что последовательные значения даты / времени должны увеличиваться в файле журнала
jfs
1
Будьте осторожны при использовании этого со временем, которое имеет доли секунды. time.mktime(datetime.datetime(2019, 8, 3, 4, 5, 6, 912000).timetuple())приводит к 1564819506.0тихому отбрасыванию миллисекунд, но datetime.datetime(2019, 8, 3, 4, 5, 6, 912000).timestamp()(ответ Анджея Пронобиса) приводит 1564819506.912к ожидаемому результату.
Алекс
128

Начиная с Python 3.3 это становится очень легко с этим datetime.timestamp()методом. Это, конечно, будет полезно, только если вам нужно количество секунд с 1970-01-01 UTC.

from datetime import datetime
dt = datetime.today()  # Get timezone naive now
seconds = dt.timestamp()

Возвращаемым значением будет число с плавающей точкой, представляющее четные доли секунды. Если datetime является часовым поясом наивным (как в примере выше), предполагается, что объект datetime представляет местное время, т.е. это будет количество секунд с текущего времени в вашем местоположении до 1970-01-01 UTC.

Анджей Пронобис
источник
3
Кто бы это ни отрицал, не могли бы вы объяснить, почему?
Анджей Пронобис
5
Я предполагаю, что понижение связано с тегом python-2.7 в вопросе (это только предположение).
Jfs
3
Это должен быть принятый ответ / принятый ответ должен быть соответствующим образом обновлен.
DreamFlasher
11
Время для обновления, я думаю;)
DreamFlasher
можно рассчитать это расстояние от другой даты начала? (Я имею в виду изменить дату 1970-01-01)
гранулы pellerossa
29

Может быть, не по теме: получить UNIX / POSIX время от datetime и преобразовать его обратно:

>>> import datetime, time
>>> dt = datetime.datetime(2011, 10, 21, 0, 0)
>>> s = time.mktime(dt.timetuple())
>>> s
1319148000.0

# and back
>>> datetime.datetime.fromtimestamp(s)
datetime.datetime(2011, 10, 21, 0, 0)

Обратите внимание, что различные часовые пояса влияют на результаты, например, мои текущие значения TZ / DST:

>>>  time.mktime(datetime.datetime(1970, 1, 1, 0, 0).timetuple())
-3600 # -1h

поэтому следует рассмотреть возможность нормализации к UTC с использованием версий функций UTC.

Обратите внимание, что предыдущий результат может быть использован для расчета смещения UTC вашего текущего часового пояса. В этом примере это + 1 час, то есть UTC + 0100.

Ссылки:

Роберт Лужо
источник
mktime()может потерпеть неудачу . В общем, вам нужно pytzпреобразовать местное время в utc, чтобы получить метку времени POSIX.
Jfs
calendar.timegm (), по-видимому, является utc-версией time.mktime ()
frankster
27

int (t.strftime("%s")) также работает

dan3
источник
1
У меня работает в Python 2.7, с import datetime; t = datetime.datetime(2011, 10, 21, 0, 0)(как указано OP). Но на самом деле, я сомневаюсь, что% s - это недавно добавленный формат времени.
Дан3
1
@ дан3: неправильно. %sне поддерживается (это может работать на некоторых платформах, если tэто простой объект datetime, представляющий местное время, и если локальная библиотека C имеет доступ к базе данных tz, в противном случае результат может быть неправильным). Не используйте это.
Jfs
%sнигде не документировано. Я посеял это в реальном коде, и мне было интересно, что это такое, и посмотрите в документации, а такой вещи нет %s. Есть только с большим S только на секунды.
В.С.Тойков
13

из документации по питону:

timedelta.total_seconds()

Возвращает общее количество секунд, содержащихся в продолжительности. Эквивалентно

(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6

вычисляется с включенным истинным делением.

Обратите внимание, что для очень больших временных интервалов (более 270 лет на большинстве платформ) этот метод теряет микросекундную точность.

Эта функциональность является новой в версии 2.7.

Майкл
источник
1
Существует небольшая проблема с вычислением, это должно быть 10 6 вместо 10 * 6 ... td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 6) / 10 ** 6
sdu
@sdu отличный улов - двойная звездочка в моем ответе, но stackoverflow использует его, пытается исправить, только подбодрить текст.
Майкл
2

Чтобы преобразовать объект datetime, который представляет время в формате UTC, в метку времени POSIX :

from datetime import timezone

seconds_since_epoch = utc_time.replace(tzinfo=timezone.utc).timestamp()

Чтобы преобразовать объект datetime, представляющий время в местном часовом поясе, в метку времени POSIX:

import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone()
seconds_since_epoch = local_timezone.localize(local_time, is_dst=None).timestamp()

См. Как мне конвертировать местное время в UTC в Python? Если база данных tz доступна на данной платформе; может работать только решение stdlib .

Перейдите по ссылкам, если вам нужны решения для <3.3версий Python.

JFS
источник
1

Я попробовал календарь calendar.timegm в стандартной библиотеке, и он работает довольно хорошо:

# convert a datetime to milliseconds since Epoch
def datetime_to_utc_milliseconds(aDateTime):
    return int(calendar.timegm(aDateTime.timetuple())*1000)

Ссылка: https://docs.python.org/2/library/calendar.html#calendar.timegm

Шаохонг Ли
источник
это лишает доли секунды. Предполагается, что aDateTimeэто время UTC
JFS