отримати часову позначку UTC у python із датою та часом


83

Чи є спосіб отримати часову позначку UTC, вказавши дату? Що я би очікував:

datetime(2008, 1, 1, 0, 0, 0, 0)

має призвести до

 1199145600

Створення наївного об'єкта дати і часу означає, що інформація про часовий пояс відсутня. Якщо я переглядаю документацію для datetime.utcfromtimestamp, створення часової позначки UTC означає залишення інформації про часовий пояс. Отже, я здогадуюсь, що створення наївного об’єкту datetime (як я це зробив) призведе до позначки часу UTC. Однак:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

призводить до

2007-12-31 23:00:00

Чи все ще є прихована інформація про часовий пояс в об’єкті datetime? Що я роблю не так?


проблема полягає в then.strftime('%s')тому, що очікується місцевий час, але мітка часу вказує, що datetime(2008, 1, 1)в UTC.
jfs

Відповіді:


91

Наївний datetimeпроти обізнаногоdatetime

datetimeОб'єкти за замовчуванням називаються "наївними": вони зберігають інформацію про час без інформації про часовий пояс. Подумайте про наїв datetimeяк відносне число (тобто:) +4без чіткого походження (насправді ваше походження буде загальним по всій межі вашої системи).

Навпаки, думайте про усвідомлені datetimeяк абсолютні числа (тобто:) 8із загальним походженням для всього світу.

Без інформації про часовий пояс ви не можете перетворити "наївну" дату і час у будь-яке неївне подання часу (звідки +4цілі, якщо ми не знаємо, з чого почати?). Ось чому у вас не може бути datetime.datetime.toutctimestamp()методу. (пор .: http://bugs.python.org/issue1457227 )

Щоб перевірити, чи ваш datetime dtнаївний, перевірте dt.tzinfo, якщо None, то це наївний:

datetime.now()        ## DANGER: returns naïve datetime pointing on local time
datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time

У мене є наївні дати, що я можу зробити?

Ви повинні зробити припущення залежно від вашого конкретного контексту: Питання, яке ви повинні задати собі, таке: чи були ви datetimeна UTC? чи це був місцевий час?

  • Якщо ви використовували UTC (у вас неприємності):

    import calendar
    
    def dt2ts(dt):
        """Converts a datetime object to UTC timestamp
    
        naive datetime will be considered UTC.
    
        """
    
        return calendar.timegm(dt.utctimetuple())
    
  • Якщо ви НЕ використовували UTC , ласкаво просимо до біса.

    Ви повинні зробити своїх datetimeненаївних перед використанням попередньої функції, повернувши їм передбачений часовий пояс.

    Вам знадобиться назва часового поясу та інформація про те, чи діяв літній час на час створення цільової наївної дати та часу (остання інформація про літній час потрібна для кутових шаф):

    import pytz     ## pip install pytz
    
    mytz = pytz.timezone('Europe/Amsterdam')             ## Set your timezone
    
    dt = mytz.normalize(mytz.localize(dt, is_dst=True))  ## Set is_dst accordingly
    

    Наслідки ненаданняis_dst :

    Невикористання is_dstгенерує неправильний час (і часову позначку UTC), якщо цільова дата і час були створені під час встановлення зворотного літнього часу (наприклад, зміна часу літнього часу, вилучивши одну годину).

    Забезпечення неправильного is_dstдозволить, звичайно, генерувати неправильний час (і часову позначку UTC) лише для перекриття літнього часу або дірок. І, якщо буде надано також неправильний час, що трапляється в "дірах" (час, який ніколи не існував через перехід на літній час), is_dstдасть тлумачення того, як вважати цей фіктивний час, і це єдиний випадок, коли .normalize(..)насправді щось робитимуть тут, оскільки він потім перекладе його як фактично дійсний час (змінюючи дату та час на літній час, якщо потрібно). Зверніть увагу, що .normalize()це не потрібно для правильної позначки часу UTC в кінці, але, ймовірно, рекомендується, якщо вам не подобається ідея мати помилковий час у ваших змінних, особливо якщо ви повторно використовуєте цю змінну в іншому місці.

    та УНИКНІТЬ ВИКОРИСТАННЯ НАСТУПНИХ : (пор .: Перетворення часового поясу дати та часу за допомогою pytz )

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    

    Чому? оскільки .replace()замінює сліпо tzinfoбез урахування цільового часу і вибере поганий об'єкт літнього часу. Тоді як .localize()використовується цільовий час та ваша is_dstпідказка для вибору правильного об’єкта літнього часу.

СТАРА неправильна відповідь (спасибі @JFSebastien за підказку):

Сподіваємось, досить легко вгадати часовий пояс (ваше місцеве походження), коли ви створюєте свій наївний datetimeоб’єкт, оскільки він пов’язаний із конфігурацією системи, яку ви, сподіваємось, НЕ міняли між створенням наївного об’єкту дати і часу, коли ви хочете отримати Позначка часу UTC. Цим фокусом можна задати недосконале запитання.

За допомогою time.mktimeми можемо створити utc_mktime:

def utc_mktime(utc_tuple):
    """Returns number of seconds elapsed since epoch

    Note that no timezone are taken into consideration.

    utc tuple must be: (year, month, day, hour, minute, second)

    """

    if len(utc_tuple) == 6:
        utc_tuple += (0, 0, 0)
    return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0))

def datetime_to_timestamp(dt):
    """Converts a datetime object to UTC timestamp"""

    return int(utc_mktime(dt.timetuple()))

Ви повинні переконатися, що ваш datetimeоб'єкт створено в тому ж часовому поясі, що і той, який створив ваш datetime.

Це останнє рішення є неправильним, оскільки воно робить припущення, що зміщення UTC відтепер є таким самим, як зміщення UTC від EPOCH. Що не стосується багатьох часових поясів (у певний момент року для зсувів літнього часу).


4
Наївний об'єкт дати і часу завжди повинен представляти час у UTC. Інші часові пояси слід використовувати лише для введення / виводу (дисплей). У datetime.timestamp()Python 3.3 є метод.
jfs

2
time.mktime()слід використовувати лише за місцевим часом. calendar.timegm()може бути використаний для перетворення набору часу utc в позначку часу. Або ще краще використовувати лише методи дати та часу. Дивіться мою відповідь
jfs

4
-1. Ваш код передбачає, що utc_offset (зараз) і utc_offset (епоха) однакові в місцевому часовому поясі. Це не так у 116 часових поясах (з 430 загальних часових поясів).
jfs

1
все ще -1: не використовувати .replace()з часовим поясом, який має нефіксоване зміщення utc, таке як 'Europe/Amsterdam'. Див. Перетворення часового поясу Datetime за допомогою pytz .
jfs

1
1- Чи розумієте ви, чому не слід використовувати .replace(tzinfo=get_localzone())? 2- timegm()повертається intвже. Не потрібно обгортати int. Крім того, .timetuple()падає частки секунди.
jfs

30

Інша можливість:

d = datetime.datetime.utcnow()
epoch = datetime.datetime(1970,1,1)
t = (d - epoch).total_seconds()

Це працює, оскільки і "d", і "епоха" є наївними датами, що робить оператор "-" дійсним і повертає інтервал. total_seconds()перетворює інтервал у секунди. Зверніть увагу, що total_seconds()повертає плаваюче число, навітьd.microsecond == 0


12
Ну насправді, ідея однакова, але цю легше зрозуміти :)
Натім,

3
Можна подумати, що в бібліотеці часу буде єдиний метод чи щось ... sheesh
wordsforthewise

Щоб отримати позначку часу, виконайте datetime.datetime.utcnow (). Timestamp ()
Євген


13

Якщо введений об’єкт datetime знаходиться у UTC:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0

Примітка: він повертає float, тобто мікросекунди представлені як частки секунди.

Якщо об’єкт дати введення в UTC:

>>> from datetime import date
>>> utc_date = date(2008, 1, 1)
>>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
1199145600

Детальніше див. У розділі Перетворення datetime.date у позначку часу UTC у Python .


8

Я відчуваю, що головна відповідь все ще не така однозначна, і варто витратити час, щоб зрозуміти час та часові пояси .

Найголовніше, що слід розуміти, маючи справу з часом, - це те, що час відносний !

  • 2017-08-30 13:23:00: (наївний час), представляє місцевий час десь у світі, але зверніть увагу, що 2017-08-30 13:23:00в Лондоні НЕ ТАКИЙ самий час, як 2017-08-30 13:23:00у Сан-Франциско.

Оскільки один і той же рядок часу можна інтерпретувати як різні моменти часу залежно від того, де ви знаходитесь у світі, існує потреба в абсолютному понятті часу.

UTC мітка часу являє собою число в секундах (або мілісекундах) від епохи (визначається як 1 January 1970 00:00:00при GMTтимчасової зони +00: 00 зміщення).

Епоха закріплена за часовим поясом GMT, і тому є абсолютним моментом часу. AUTC мітка часу будучи зміщення від абсолютного часу , отже , визначає абсолютну точку в часі .

Це дає можливість вчасно замовляти події.

Без інформації про часовий пояс час є відносним і не може бути перетворений в абсолютне поняття часу без надання певних вказівок, до якого часового поясу має бути прив'язаний наївний час.

Які типи часу використовуються в комп’ютерній системі?

  • наївний час і дату : зазвичай для відображення, за місцевим часом (тобто в браузері), де ОС може надавати програмі інформацію про часовий пояс.

  • Часові позначки UTC : Мітка часового поясу UTC є абсолютним моментом часу, як уже згадувалося вище, але вона закріплена в певному часовому поясі, тому часову позначку UTC можна перетворити на дату в будь-якому часовому поясі, однак вона не містить інформації про часовий пояс. Що це означає? Це означає, що 1504119325 відповідає 2017-08-30T18:55:24Z, 2017-08-30T17:55:24-0100або також 2017-08-30T10:55:24-0800. Це не говорить вам, звідки записана дата та час. Зазвичай він використовується на стороні сервера для запису подій (журналів тощо) або використовується для перетворення часового поясу, визначеного часовим поясом, в абсолютний момент часу та обчислення час, різниці в часі .

  • ISO-8601 DateTime рядок: ISO-8601 являє собою стандартизований формат для запису дати і часу з тимчасової зоною. (Це насправді кілька форматів, читайте тут: https://en.wikipedia.org/wiki/ISO_8601 ) Використовується для передачі інформації про дату та час, відому часовому поясу, серіалізуючим чином між системами.

Коли використовувати який? вірніше, коли вам потрібно піклуватися про часові пояси?

  • Якщо вам потрібно будь-яким чином піклуватися про час доби , вам потрібна інформація про часовий пояс. Для календаря або будильника потрібен час доби, щоб встановити зустріч у правильний час доби для будь-якого користувача у світі. Якщо ці дані зберігаються на сервері, сервер повинен знати, якому часовому поясу відповідає дата і час.

  • Для обчислення різниці в часі між подіями, що походять з різних місць світу, достатньо часової позначки UTC, але ви втрачаєте можливість аналізувати, в який час доби відбувалися події (тобто для веб-аналітики ви можете знати, коли користувачі приходять до вашого сайт в їх місцевий час : ви бачите більше користувачів вранці або ввечері робити ви не можете зрозуміти , що без інформації про часу доби.

Зміщення часового поясу в рядку дати :

Іншим важливим моментом є те, що зміщення часового поясу в рядку дати не фіксовано . Це означає, що те, що 2017-08-30T10:55:24-0800каже компенсація -0800або 8 годин назад, не означає, що це буде завжди!

Влітку цілком може бути перехід на літній час, і це могло б бути -0700

Це означає, що зміщення часового поясу (+0100) - це не те саме, що назва часового поясу (Європа / Франція) або навіть позначення часового поясу (CET)

America/Los_Angelesчасовий пояс - місце у світі , але воно перетворюється на PST(тихоокеанський стандартний час) часовий пояс, зміщений у зимовий час, та PDT(тихоокеанський денний час) влітку.

Отже, на додаток до отримання часового поясу, зміщеного з датчика, ви також повинні отримати назву часового поясу, щоб бути точною.

Більшість пакетів зможуть самостійно перетворити числові зсуви з переходу на літній час у стандартний час, але це не обов’язково тривіально при простому зміщенні. Наприклад, WATпозначення часового поясу в Західній Африці становить UTC + 0100, як іCET часовий пояс у Франції, але Франція дотримується переходу на літній час, тоді як Західна Африка цього не робить (оскільки вони знаходяться близько до екватора)

Отож, словом, це складно. ДУЖЕ складно, і тому вам не слід робити це самостійно, а довіряйте пакету, який робить це за вас, і ДЕРЖАЙТЕ ДО СУЧАСНОСТІ!


перегляньте мою публікацію в блозі про дату та час у Python, щоб зрозуміти підводні камені різних пакетів medium.com/@eleroy/…
MrE

3

Просте рішення без використання зовнішніх модулів:

from datetime import datetime, timezone

dt = datetime(2008, 1, 1, 0, 0, 0, 0)
int(dt.replace(tzinfo=timezone.utc).timestamp())


1

Я думаю, що правильний спосіб сформулювати ваше запитання Is there a way to get the timestamp by specifying the date in UTC?, оскільки мітка часу - це лише число, яке є абсолютним, а не відносним. Відносним фрагментом (або часовим поясом) є дата.

Я вважаю панди дуже зручними для позначок часу, тому:

import pandas as pd
dt1 = datetime(2008, 1, 1, 0, 0, 0, 0)
ts1 = pd.Timestamp(dt1, tz='utc').timestamp()
# make sure you get back dt1
datetime.utcfromtimestamp(ts1)  

Використання панд - це правильний підхід IMHO, для поточного часу існує також t = Timestamp.utcnow (), щоб безпосередньо отримати потрібний час :)
ntg,

0

Прийнята відповідь, здається, не працює для мене. Моє рішення:

import time
utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple()))
def datetime2ts(dt):
    """Converts a datetime object to UTC timestamp"""
    return int(time.mktime(dt.utctimetuple())) - utc_0

це не вдається, якщо поточний ( dt) UTC зміщення місцевого часового поясу і в 1970 р. відрізняються. mktime()очікує місцевий час.
jfs

0

Найпростіший спосіб:

>>> from datetime import datetime
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> dt.strftime("%s")
'1199163600'

Редагувати: @Daniel правильний, це перетворило б його на часовий пояс машини. Ось переглянута відповідь:

>>> from datetime import datetime, timezone
>>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0, timezone.utc)
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0, timezone.utc)
>>> int((dt-epoch).total_seconds())
'1199145600'

Насправді це навіть не потрібно вказувати timezone.utc, оскільки різниця в часі однакова, якщо обидва datetimeмають однаковий часовий пояс (або відсутність часового поясу).

>>> from datetime import datetime
>>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0)
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> int((dt-epoch).total_seconds())
1199145600

цей метод не повертає utc, а скоріше пристосовує дату до поточного часового поясу. тобто якщо зараз 12:00 в тз +3, то повернеться 9 ранку в епоху.
Даніель Дубовський

Ах ти маєш рацію. Мій часовий пояс був UTC - саме тому він працював.
Майк Фурлендер

Якщо ви збираєтесь використовувати timezone.utcоб'єкт (Python 3.2 і новіші) , тоді просто використовуйте його з .timestamp():datetime(2008, 1, 1, tzinfo=timezone.utc).timestamp() . Не потрібно створювати об’єкт епохи і віднімати ..
Мартін Пітерс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.