получить метку времени 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 ответов:
что такое наивный
datetime
?по умолчанию
datetime
объекты считаются "наивными": они хранят информацию о времени без информации о часовом поясе. Подумайте о наивномdatetime
как относительное число (т. е.:+4
) без четкого происхождения (на самом деле ваше происхождение будет общим на всей границе вашей системы). Подумайте о сознанииdatetime
как абсолютные числа (т. е.:8
) С общим началом для всего мира.без информации о часовом поясе вы не можете преобразуйте "наивную" дату-время в любое не наивное представление времени (где
+4
цели, если мы не знаем, с чего начать ?). Вот почему вы не можете иметьdatetime.datetime.toutctimestamp()
метод. (cf: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 (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
atGMT
часовой пояс +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