Подтвердить что ты не робот

Получить метку времени UTC в python с датой

Есть ли способ получить временную метку UTC, указав дату? Что я ожидаю:

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

должно привести к

 1199145600

Создание наивного объекта datetime означает, что нет информации о часовом поясе. Если я посмотрю документацию по 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? Что я делаю неправильно?

4b9b3361

Ответ 1

Наивный 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 не наивным, прежде чем использовать первый функция, возвращая им предполагаемый часовой пояс.

    Вам понадобится название часового пояса и информация о если DST действовал при создании целевого наивного datetime ( последняя информация о DST требуется для angular шкафов):

    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) только на DST перекрытия или дыр. И когда обеспечение также неверное время, происходящее в "дырах" (время, которого никогда не было из-за для перехода вперед по DST), is_dst даст интерпретацию как считать это фиктивное время, и это единственный случай, когда .normalize(..) на самом деле что-то здесь сделает, как тогда перевести его как фактическое действительное время (изменение даты и времени Объект DST, если требуется). Обратите внимание, что .normalize() не требуется за правильную временную метку UTC в конце, но, вероятно, рекомендуется, если вам не нравится идея иметь фиктивные времена в вашем переменные, особенно если вы повторно используете эту переменную в другом месте.

    и ИЗБЕГАЙТЕ ИСПОЛЬЗОВАНИЯ СЛЕДУЮЩЕГО: (ср.: преобразование даты и времени в часовой пояс с использованием pytz)

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

    Почему? потому что .replace() слепо заменяет tzinfo без с учетом целевого времени и выберет плохой объект DST. Принимая во внимание, что .localize() использует целевое время и вашу подсказку is_dst выбрать правильный объект DST.

СТАРЫЙ неправильный ответ (спасибо @J.F.Sebastien за это):

Надеемся, что при создании вашего наивного объекта datetime довольно легко угадать часовой пояс (ваш локальный источник), поскольку он связан с конфигурацией системы, которую вы, надеюсь, НЕ изменили бы между созданием наивного объекта 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. Что не относится ко многим часовым поясам (в определенный момент года для смещения летнего времени (DST)).

Ответ 2

Другая возможность:

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

Это работает как "d", так и "epoch" - наивные datetimes, что делает оператор "-" действительным и возвращает интервал. total_seconds() превращает интервал в секунды. Обратите внимание, что total_seconds() возвращает float, даже d.microsecond == 0

Ответ 3

Также обратите внимание на функцию calendar.timegm(), как описано в этой записи в блоге:

import calendar
calendar.timegm(utc_timetuple)

Выход должен совпадать с решением vaab.

Ответ 4

Если входной объект 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.

Ответ 5

Мне кажется, что основной ответ до сих пор не так ясен, и стоит потратить время на понимание часовых и часовых поясов.

Самое важное, что нужно понимать при работе со временем, это то, что время является относительным!

  • 2017-08-30 13:23:00: (наивное время даты) представляет местное время где-то в мире, но учтите, что 2017-08-30 13:23:00 в Лондоне НЕ ЖЕ ВРЕМЯ, как 2017-08-30 13:23:00 в Сан Франциско.

Поскольку одну и ту же строку времени можно интерпретировать как разные моменты времени в зависимости от того, где вы находитесь в мире, необходимо абсолютное представление о времени.

UTC timestamp - это число в секундах (или миллисекундах) от эпохи (определяется как 1 January 1970 00:00:00 в часовом поясе GMT +00: смещение 00).

Эпоха привязана к часовому поясу GMT и, следовательно, является абсолютным моментом времени. Таким образом, временная метка UTC, являющаяся смещением от абсолютного времени, определяет абсолютный момент времени.

Это позволяет упорядочивать события во времени.

Без информации о часовом поясе время является относительным и не может быть преобразовано в абсолютное понятие времени без предоставления какого-либо указания на то, к какому часовому поясу должна быть привязана наивная дата-время.

Какие типы времени используются в компьютерной системе?

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

  • Отметки времени UTC. Отметка времени UTC является абсолютным моментом времени, как упомянуто выше, но она привязана к заданному часовому поясу, поэтому отметку времени UTC можно преобразовать в дату/время в любом часовом поясе, однако он не содержит информацию о часовом поясе. Что это обозначает? Это означает, что 1504119325 соответствует 2017-08-30T18:55:24Z, или 2017-08-30T17:55:24-0100, или также 2017-08-30T10:55:24-0800. Он не сообщает вам откуда дата и время записи. Обычно он используется на стороне сервера для записи событий (журналов и т.д.) Или используется для преобразования даты/времени с учетом часового пояса в абсолютный момент времени и вычисления времени различия.

  • Строка date-time ISO-8601: 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 во Франции, но во Франции наблюдается переход на летнее время, а в Западной Африке - нет (потому что они близки к экватору)

Короче говоря, это сложно. ОЧЕНЬ сложно, и именно поэтому вы не должны делать это самостоятельно, но доверяйте пакету, который делает это за вас, и СОХРАНИТЕ ЭТО ДО ДАТЫ!

Ответ 7

Принятый ответ кажется мне неэффективным. Мое решение:

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

Ответ 8

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

from datetime import datetime, timezone

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

Ответ 9

Самый простой способ:

>>> 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