получить метку времени UTC в python с указанием даты и времени - PullRequest
67 голосов
/ 21 февраля 2011

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

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

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

 1199145600

Создание наивного объекта даты и времени означает, что информация о часовом поясе отсутствует.Если я посмотрю документацию для datetime.utcfromtimestamp, то создание метки времени в формате UTC означает отсутствие информации о часовом поясе.Поэтому я бы предположил, что создание наивного объекта даты и времени (как я это сделал) приведет к отметке времени UTC.Однако:

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

приводит к

2007-12-31 23:00:00

Есть ли еще скрытая информация о часовом поясе в объекте datetime?Что я делаю не так?

Ответы [ 8 ]

73 голосов
/ 31 марта 2011

Что такое наивный 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 при создании целевого наивного даты / времени (последняя информация о DST требуется для угловых случаев):

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

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

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

    Почему?потому что .replace() слепо заменяет tzinfo без учета целевого времени и выберет плохой объект DST.Принимая во внимание, что .localize() использует целевое время и подсказку is_dst для выбора правильного объекта 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. Что не так для многих часовых поясов (в конкретный момент года для смещения летнего времени (DST)).

22 голосов
/ 28 февраля 2014

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

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

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

19 голосов
/ 11 июля 2012

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

import calendar
calendar.timegm(utc_timetuple)

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

12 голосов
/ 16 ноября 2012

Если введенный объект даты и времени находится в UTC:

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

Примечание. Возвращает значение с плавающей запятой, т. Е. Микросекунды представлены в долях секунды.

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

6 голосов
/ 30 августа 2017

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

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

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

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

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

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

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

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

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

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

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

  • ISO-8601 datetime string: 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 (Pacific Standard Time), иPDT (тихоокеанское летнее время) летом.

Итак, помимо получения смещения часового пояса от строки даты, вы также должны получить точное имя часового пояса.

Большинство пакетовсможет преобразовывать числовые смещения из летнего времени в стандартное время самостоятельно, но это не обязательно тривиально с простым смещением.Например, WAT обозначение часового пояса в Западной Африке, это UTC + 0100, точно так же, как CET часовой пояс во Франции, но Франция наблюдает за переходом на летнее время, в то время как Западная Африка не (потому что они близки к экватору)1158 * Короче говоря, это сложно.ОЧЕНЬ сложно, и поэтому вам не следует делать это самостоятельно, но доверять пакету, который сделает это за вас, и СОХРАНЯЙТЕ ЭТО ДО ДАТЫ!

1 голос
/ 21 февраля 2011

Действительно, существует проблема с использованием utcfromtimestamp и указанием часовых поясов.Хороший пример / объяснение доступно по следующему вопросу:

Как указать часовой пояс (UTC) при конвертации в Unix-время?(Python)

0 голосов
/ 21 февраля 2018

Простейший способ:

>>> 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
0 голосов
/ 22 февраля 2014

Принятый ответ не работает для меня.Мое решение:

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