Преобразование времени RFC 3339 в стандартную метку времени Python

Есть ли простой способ преобразовать время RFC 3339 в обычную метку времени Python?

У меня есть сценарий, который читает канал ATOM, и я хотел бы иметь возможность сравнивать метку времени элемента в канале ATOM со временем модификации файла.

Я заметил из спецификации ATOM, что ATOM даты включают смещение часового пояса (Z<a number>), но в моем случае после Z ничего нет, поэтому я думаю, мы можем предположить GMT.

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


person Mark Biek    schedule 21.12.2009    source источник
comment
Если вы прочитаете спецификацию RFC 3339, вы увидите, что единственными допустимыми значениями смещения часового пояса являются: (0) пустая буква Z, означающая, что метка времени - UTC; или (1) смещение в форме [+ -] \ d \ d: \ d \ d, например +02: 00 или -08: 00. Обратите внимание, что смещение +00: 00 будет означать то же самое, что и Z. Подробнее см. Спецификацию RFC 3339: tools.ietf.org/html/rfc3339   -  person steveha    schedule 14.03.2011


Ответы (15)


Нет встроенного, афайк.

feed.date.rfc3339 Это модуль библиотеки Python с функциями для преобразования строк меток времени в формате RFC 3339 в значения времени с плавающей запятой Python и наоборот. RFC 3339 - это формат метки времени, используемый форматом синдикации каналов Atom.

Имеет лицензию BSD.

http://home.blarg.net/~steveha/pyfeed.html

(Отредактировано, так что ясно, что я не писал его. :-)

person Alex Brasetvik    schedule 21.12.2009
comment
PyFeed делает именно то, что мне нужно, благодаря функции tf_from_timestamp () в feed.date.rfc3339 - person Mark Biek; 21.12.2009
comment
Кроме того, я написал библиотеки PyFeed (и Xe) и болтаюсь здесь, в StackOverflow, поэтому, если у вас есть какие-либо вопросы по этому поводу, я с радостью отвечу на них. - person steveha; 21.12.2009
comment
Обратите внимание, что PyFeed можно использовать для анализа канала Atom. Он использует xml.dom.minidom для фактического анализа, а затем распаковывает древовидную структуру XML в красивые удобные классы. Хм, мне надо поставить Xe и PyFeed на PyPI. - person steveha; 21.12.2009
comment
@steveha Отлично, спасибо за предложение. Пока что библиотеки кажутся довольно простыми в использовании, но я запомню, что вы здесь, если столкнусь с чем-нибудь странным. - person Mark Biek; 21.12.2009
comment
@Alex Brasetvik, уже было ясно, что вы не утверждали, что написали это. Если бы вы запрашивали кредит, вы бы не добавили прямую ссылку на мою веб-страницу! P.S. Я был рад видеть, что вы рекомендуете мою библиотеку; Спасибо. - person steveha; 22.12.2009

Вы не включаете пример, но если у вас нет Z-смещения или часового пояса, и если вы предполагаете, что вам нужны не длительности, а только базовое время, то, возможно, это вам подойдет:

import datetime as dt
>>> dt.datetime.strptime('1985-04-12T23:20:50.52', '%Y-%m-%dT%H:%M:%S.%f')
datetime.datetime(1985, 4, 12, 23, 20, 50, 520000)

Функция strptime () была добавлена ​​в модуль datetime в Python 2.5, поэтому некоторые люди еще не знают о ней.

Изменить: функция time.strptime () существует некоторое время и работает примерно так же, чтобы дать вам значение struct_time:

>>> ts = time.strptime('1985-04-12T23:20:50.52', '%Y-%m-%dT%H:%M:%S.%f')
>>> ts
time.struct_time(tm_year=1985, tm_mon=4, tm_mday=12, tm_hour=23, tm_min=20, tm_sec=50, tm_wday=4, tm_yday=102, tm_isdst=-1)
>>> time.mktime(ts)
482210450.0
person Peter Hansen    schedule 21.12.2009
comment
Это не сработает - методы, не учитывающие часовые пояса, несовместимы с RFC 3339. - person Yarin; 19.12.2011
comment
Ярин, ясно, но ваша жалоба должна быть связана с использованием RFC 3339 в исходном вопросе, поскольку мой ответ действительно касался его фактического вопроса, где он отмечает, что у него нет часового пояса ... - person Peter Hansen; 01.01.2012
comment
Питер: Как я читал его вопрос, он пытается сравнить дату RFC 3999 канала ATOM с часовым поясом с другой датой с предполагаемым временем по Гринвичу, но, возможно, я этого не понимаю. - person Yarin; 01.03.2012
comment
@Yarin: после Z ничего нет - это означает, что введено UTC и можно использовать strptime(). Хотя mktime(), который ожидает время в местном часовом поясе, использовать не следует. Вместо этого можно использовать calendar.timegm() (для сравнения с результатом os.path.getmtime(): я хотел бы иметь возможность сравнивать метку времени элемента в фиде ATOM со временем модификации файла.) - person jfs; 04.09.2015

Я много боролся с форматом datetime RFC3339, но я нашел подходящее решение для преобразования date_string ‹=> datetime_object в обоих направлениях.

Вам нужны два разных внешних модуля, потому что один из них может выполнять преобразование только в одном направлении (к сожалению):

первая установка:

sudo pip install rfc3339
sudo pip install iso8601

затем включите:

import datetime     # for general datetime object handling
import rfc3339      # for date object -> date string
import iso8601      # for date string -> date object

Чтобы не запоминать, какой модуль для какого направления, я написал две простые вспомогательные функции:

def get_date_object(date_string):
  return iso8601.parse_date(date_string)

def get_date_string(date_object):
  return rfc3339.rfc3339(date_object)

которые внутри вашего кода вы можете легко использовать следующим образом:

input_string = '1989-01-01T00:18:07-05:00'
test_date = get_date_object(input_string)
# >>> datetime.datetime(1989, 1, 1, 0, 18, 7, tzinfo=<FixedOffset '-05:00' datetime.timedelta(-1, 68400)>)

test_string = get_date_string(test_date)
# >>> '1989-01-01T00:18:07-05:00'

test_string is input_string # >>> True

Эврика! Теперь вы можете легко (ха-ха) использовать строки даты и строки даты в удобном для использования формате.

person MenschMarcus    schedule 13.03.2016

http://pypi.python.org/pypi/iso8601/, похоже, может анализировать iso 8601, частью которого является RFC 3339, возможно, это может быть полезно, но, опять же, не встроено.

person zpon    schedule 21.12.2009
comment
Время с плавающей запятой и struct_time не учитывают часовой пояс. Поскольку RFC 3339 требует использования часовых поясов, совместимых с UTC, что в Python означает не-наивные объекты datetime, это пока единственный разумный вариант. - person Tobu; 16.09.2011

Если вы используете Django, вы можете использовать функцию Django parse_datetime:

>>> from django.utils.dateparse import parse_datetime
>>> parse_datetime("2016-07-19T07:30:36+05:00")
datetime.datetime(2016, 7, 19, 7, 30, 36, tzinfo=<django.utils.timezone.FixedOffset object at 0x101c0c1d0>)
person Flimm    schedule 26.08.2016

http://bugs.python.org/issue15873 (дубликат http://bugs.python.org/issue5207)

Похоже, встроенного пока нет.

person Amber    schedule 21.12.2009

feedparser.py предоставляет надежный / расширяемый способ анализа различных форматов даты, которые могут встречаться в реальных условиях. -world atom / rss каналы:

>>> from feedparser import _parse_date as parse_date
>>> parse_date('1985-04-12T23:20:50.52Z')
time.struct_time(tm_year=1985, tm_mon=4, tm_mday=12, tm_hour=23, tm_min=20,
                 tm_sec=50, tm_wday=4, tm_yday=102, tm_isdst=1)
person jfs    schedule 21.12.2009
comment
Это кажется намного лучше, чем временные поплавки, предлагаемые PyFeed. - person Ram Rachum; 21.11.2010
comment
cool-NR, если у вас есть значение с плавающей запятой, вы можете вызвать time.gmtime() и получить значение struct_time. А относительное время намного проще делать с помощью значения с плавающей запятой; через два дня будет просто tf + 2 * seconds_per_day (где seconds_per_day равно 24 * 60 * 60). Python struct_time отлично подходит для проверки (какой сейчас день недели?), Но ужасно неудобен для вычислений. - person steveha; 14.03.2011
comment
ссылка не работает - если она должна быть code.google.com/ п / feedparser / source / browse / trunk / feedparser /? - person Yarin; 19.12.2011
comment
Не держит миллисекунды? - person Lennart Rolland; 20.11.2019
comment
@LennartRolland: да. time.struct_time не сохраняет доли секунды. - person jfs; 20.11.2019

Новый метод datetime.fromisoformat (date_string), который был , добавленный в Python 3.7, будет анализировать большинство меток времени RFC 3339, включая метки времени. зоны смещения. Это не полная реализация, поэтому обязательно протестируйте свой вариант использования.

>>> from datetime import datetime
>>> datetime.fromisoformat('2011-11-04')
datetime.datetime(2011, 11, 4, 0, 0)
>>> datetime.fromisoformat('2011-11-04T00:05:23')
datetime.datetime(2011, 11, 4, 0, 5, 23)
>>> datetime.fromisoformat('2011-11-04 00:05:23.283')
datetime.datetime(2011, 11, 4, 0, 5, 23, 283000)
>>> datetime.fromisoformat('2011-11-04 00:05:23.283+00:00')
datetime.datetime(2011, 11, 4, 0, 5, 23, 283000, tzinfo=datetime.timezone.utc)
>>> datetime.fromisoformat('2011-11-04T00:05:23+04:00')   
datetime.datetime(2011, 11, 4, 0, 5, 23,
    tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
person dln385    schedule 25.01.2020

попробуйте это, у меня отлично работает

datetime_obj =  datetime.strptime("2014-01-01T00:00:00Z", '%Y-%m-%dT%H:%M:%SZ')

or

datetime_obj = datetime.strptime("Mon, 01 Jun 2015 16:41:40 GMT", '%a, %d %b %Y %H:%M:%S GMT')
person dfostic    schedule 19.08.2015
comment
он не поддерживает числовое смещение utc: +HHMM. Второй пример - это не rfc 3339; это rfc 5322 - person jfs; 23.09.2015

В другом вопросе наткнулся на замечательный модуль dateutil.parser и попробовал его с моей проблемой RFC3339, и, похоже, он справляется со всем Я подхожу к нему с большей здравомыслием, чем к любым другим ответам на этот вопрос.

person Bolster    schedule 27.08.2012
comment
Единственная проблема в том, что он также анализирует значения без даты, как сейчас - person Romuald Brunet; 25.02.2013

Используя Python 3, вы можете использовать RegEx, чтобы разбить временную метку RFC 3339 на компоненты. Затем напрямую создайте объект datetime, никаких дополнительных модулей не требуется:

import re
import datetime

def parse_rfc3339(dt):
    broken = re.search(r'([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.([0-9]+))?(Z|([+-][0-9]{2}):([0-9]{2}))', dt)
    return(datetime.datetime(
        year = int(broken.group(1)),
        month = int(broken.group(2)),
        day = int(broken.group(3)),
        hour = int(broken.group(4)),
        minute = int(broken.group(5)),
        second = int(broken.group(6)),
        microsecond = int(broken.group(8) or "0"),
        tzinfo = datetime.timezone(datetime.timedelta(
            hours = int(broken.group(10) or "0"),
            minutes = int(broken.group(11) or "0")))))

В этом примере отсутствующие часовые пояса или микросекунды отображаются как «0», но может потребоваться дополнительная проверка ошибок. Привет, Алекс

person Alexander Simon    schedule 07.06.2016

Самым простым решением для меня была стандартная библиотека Python dateutil.

from dateutil.parser import parse

dt = "2020-11-23T11:08:23.022277705Z"
print(parse(dt))

Вывод:

2020-11-23 11:08:23.022277+00:00

Если вам не нужен элемент часового пояса, просто установите для информации о часовом поясе значение Нет

print(parse(t).replace(tzinfo=None))

Результатом является красивый и чистый объект datetime:

2020-11-23 11:08:23.022277
person Sergej Gorev    schedule 23.11.2020

Вы можете использовать пакет Google API Core. У них действительно простая функция преобразования Datetime в RFC 3339. Дополнительную информацию можно найти в их документы.

Его использование очень простое:

from google.api_core.datetime_helpers import to_rfc3339

rfc3339_str = to_rfc3339(datetime.now())

У них даже есть функция, которая работает наоборот с from_rfc3339 и from_rfc3339_nanos.

person MxRay    schedule 19.01.2021

Библиотека rfc3339: http://henry.precheur.org/python/rfc3339

person max5555    schedule 30.08.2011

Я глубоко погрузился в dateimes и RFC3339 и недавно наткнулся на библиотеку стрелок и только что использовали и решили мою проблему:

import arrow

date_string = "2015-11-24 00:00:00+00:00"
my_datetime = arrow.get(date_string).datetime
person hum3    schedule 21.08.2020