получить метку времени UTC в python с datetime


есть ли способ получить метку времени 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? Что я делаю не так?

8 58

8 ответов:

что такое наивный datetime?

по умолчанию datetime объекты считаются "наивными": они хранят информацию о времени без информации о часовом поясе. Подумайте о наивном datetime как относительное число (т. е.: +4) без четкого происхождения (на самом деле ваше происхождение будет общим на всей границе вашей системы). Подумайте о сознании datetime как абсолютные числа (т. е.:8) С общим началом для всего мира.

без информации о часовом поясе вы не можете преобразуйте "наивную" дату-время в любое не наивное представление времени (где +4 цели, если мы не знаем, с чего начать ?). Вот почему вы не можете иметь datetime.datetime.toutctimestamp() метод. (cf:http://bugs.python.org/issue1457227)

чтобы проверить, если ваш datetimedt наивно, проверить 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 (the последняя информация о DST требуется для cornercases):

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

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

    и ИЗБЕГАЙТЕ ИСПОЛЬЗОВАНИЯ СЛЕДУЮЩИХ: (cf:преобразование часового пояса Datetime с использованием 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 от now совпадает с смещением UTC от EPOCH. что не относится к большому количеству часовых поясов (в определенный момент года для смещений летнего времени (DST)).

также обратите внимание на календарь.timegm() как рассказала этой запись в блоге:

import calendar
calendar.timegm(utc_timetuple)

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

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

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

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

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

я чувствую, что главный ответ все еще не так ясен, и стоит потратить время, чтобы понять времени и пояса.

самое главное, чтобы понять, когда речь идет о времени, что время относительные!

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

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

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

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

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

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

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

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

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

  • 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 (Тихоокеанское летнее время) летом.

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

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

короче говоря, это сложно. Очень сложно, и именно поэтому вы не должны делать это сами, но доверяйте пакет, который делает это за вас, и держать его в курсе!

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

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

принятый ответ, кажется, не работает для меня. Мое решение:

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

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

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

Edit: @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