Як в Python ви перетворюєте об’єкт `datetime` в секунди?


226

Вибачте за просте запитання ... Я новачок у Python ... Я шукав навколо, і, здається, нічого не працює.

У мене є маса об'єктів дати, і я хочу обчислити кількість секунд з фіксованого часу в минулому для кожного (наприклад, з 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.utcякщо використовуєте Python 3.


1
Тепер Python попереджає мене: "TypeError: не можна відняти зсувні наїзні та зсувні дати" Що найкраще рішення для усунення?
Аарон Еш

2
@Charybdis, спробуйте datetime.datetime(1970,1,1,tzinfo=pytz.utc).
Марк Викуп 11

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 . Усі системи, де працює пітон, використовують ту саму епоху: 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
Справді будьте обережні. Мене це покусало до великої попки
Арг

передбачається, що tце місцевий час. Зсув UTC для локального часового поясу в минулому, можливо, відрізнявся, і якщо mktime()(бібліотека С) не має доступу до історичних даних часового поясу на даній платформі, ніж може бути невдалою ( 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()

Повернене значення буде поплавком, що представляє парні частки секунди. Якщо час дати є наївним часовим поясом (як у наведеному вище прикладі), вважатиметься, що об'єкт дати представляє місцевий час, тобто це буде кількість секунд від поточного часу у вашому місці розташування до 1970-01-01 UTC.


3
Хто б не спричинив це, чи не могли б ви пояснити чому?
Анджей Пронобіс

5
Я припускаю, що нижченаведений результат пояснюється тегом python-2.7 (це лише здогадка).
jfs

3
Це має бути прийнята відповідь / прийняту відповідь слід оновити відповідно.
DreamFlasher

11
Час оновлення, мабуть;)
DreamFlasher

можна обчислити цю відстань від іншої дати початку? (я маю на увазі змінити дату 1970-01-01)
pellerossa pelles

29

Можливо поза темою: отримати час UNIX / POSIX з дати та перетворити його назад:

>>> 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 вашого поточного часового поясу. У цьому прикладі це + 1h, тобто UTC + 0100.

Список літератури:


mktime()може вийти з ладу . Загалом, вам потрібно pytzперетворити місцевий час у utc, щоб отримати часову мітку POSIX.
jfs

Calendar.timegm (), здається, є утч-версією time.mktime ()
франкстер,

27

int (t.strftime("%s")) також працює


1
Для мене працює в Python 2.7, з import datetime; t = datetime.datetime(2011, 10, 21, 0, 0)(як зазначено в OP). Але насправді, я сумніваюся,% s - це нещодавно доданий формат часу.
dan3

1
@ dan3: неправильно. %sне підтримується (він може працювати на деяких платформах iff t- це наївний об'єкт часу, що представляє місцевий час, і якщо локальна бібліотека C має доступ до бази даних tz, інакше результат може бути неправильним). Не використовуйте його.
jfs

%sніде не задокументовано. Я посіяв його в реальному коді і цікавився, що це таке, і подивіться в документацію, а такого немає як %s. Є лише з великим S лише на секунди.
В.Стойков

13

з документів python:

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

Для перетворення об'єкта дати, який представляє час у UTC, у часову позначку POSIX :

from datetime import timezone

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

Для перетворення об’єкта дати, який представляє час у локальному часовому поясі, у часову позначку 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.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.