Для ясности: ISO 8601 является основным стандартом. RFC 3339 - это самопровозглашенный «профиль» ISO 8601, который делает некоторые неразумные изменения правил ISO 8601.
Базилик Бурк
3
Не пропустите приведенное ниже решение python3.7 + для инвертирования изоформата ()
Брэд М
2
Этот вопрос не следует закрывать как дупе к связанному посту. Так как этот просит проанализировать строку времени ISO 8601 (которая изначально не поддерживалась python до 3.7), а другой - отформатировать объект datetime в строку эпохи, используя устаревший метод.
18:15
Ответы:
461
Пакет python-dateutil может анализировать не только строки даты и времени RFC 3339, как в вопросе, но также и другие строки даты и времени ISO 8601, которые не соответствуют RFC 3339 (например, те, которые не имеют смещения UTC, или те, которые представляют только свидание).
>>>import dateutil.parser
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z')# RFC 3339 format
datetime.datetime(2008,9,3,20,56,35,450686, tzinfo=tzutc())>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686')# ISO 8601 extended format
datetime.datetime(2008,9,3,20,56,35,450686)>>> dateutil.parser.isoparse('20080903T205635.450686')# ISO 8601 basic format
datetime.datetime(2008,9,3,20,56,35,450686)>>> dateutil.parser.isoparse('20080903')# ISO 8601 basic format, date only
datetime.datetime(2008,9,3,0,0)
Обратите внимание, что dateutil.parser.isoparseпредположительно строже, чем более хакерскийdateutil.parser.parse , но оба они довольно просты и попытаются интерпретировать передаваемую вами строку. Если вы хотите исключить возможность каких-либо неправильных прочтений, вам нужно использовать что-то более строгое, чем любой из этих функции.
Для ленивых, он установлен с помощью python-dateutilне dateutilтак: pip install python-dateutil.
cod3monk3y
29
Имейте в виду, что dateutil.parserон намеренно взломан: он пытается угадать формат и делает неизбежные предположения (настраиваемые только вручную) в неоднозначных случаях. Так что используйте его ТОЛЬКО, если вам нужно разобрать ввод неизвестного формата, и вы можете терпеть случайные неправильные чтения.
ivan_pozdeev
2
Согласовано. Например, передается «дата» 9999. Это будет возвращать то же самое, что и дата-время (9999, текущий месяц, текущий день). На мой взгляд, недопустимая дата.
Тимбо
1
@ivan_pozdeev, какой пакет вы бы порекомендовали для не угадывающего анализа?
bgusach
2
@ivan_pozdeev есть обновление модуля, который читает даты iso8601
theEpsilon
198
Новое в Python 3.7+
В datetimeстандартной библиотеке появилась функция инвертирования datetime.isoformat().
Это странно. Поскольку a datetimeможет содержать a tzinfoи, следовательно, выводить часовой пояс, но datetime.fromisoformat()не анализирует tzinfo? похоже на ошибку ..
Хенди Ираван
20
Не пропустите эту заметку в документации, она не принимает все допустимые строки ISO 8601, только те, которые сгенерированы isoformat. Он не принимает пример в вопросе "2008-09-03T20:56:35.450686Z"из-за трейлинга Z, но он принимает "2008-09-03T20:56:35.450686".
Flimm
26
Для правильной поддержки Zвходной скрипт можно изменить с помощью date_string.replace("Z", "+00:00").
Jox
7
Обратите внимание, что за секунды он обрабатывает только 0, 3 или 6 десятичных знаков. Если входные данные имеют 1, 2, 4, 5, 7 или более десятичных знаков, синтаксический анализ завершится неудачно!
Felk
1
@JDOaktown В этом примере используется нативная библиотека даты и времени Python, а не парсер dateutil. Это на самом деле потерпит неудачу, если при таком подходе десятичные разряды не равны 0, 3 или 6.
abccd
174
Обратите внимание, что в Python 2.6+ и Py3K символ% f перехватывает микросекунды.
Примечание - если вы используете наивные даты и времени - я думаю, что вы вообще не получите TZ - Z может не совпадать ни с чем.
Дэнни Стейпл
24
Этот ответ (в его текущей отредактированной форме) основан на жестком кодировании определенного смещения UTC (а именно «Z», что означает +00: 00) в строку формата. Это плохая идея, потому что она не сможет проанализировать любое время и дату с другим смещением UTC и вызвать исключение. Смотрите мой ответ, который описывает, как strptimeна самом деле невозможно выполнить разбор RFC 3339 .
Марк Амери
1
в моем случае% f поймал микросекунды, а не Z, datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f') так что
сработало
Py3K означает Python 3000?!?
Робиньо
2
@Robino IIRC, «Python 3000» - это старое название для того, что сейчас известно как Python 3.
Предполагая, что вы хотите поддерживать полный формат RFC 3339, включая поддержку смещений UTC, отличных от нуля, код, предлагаемый этими ответами, не работает. Действительно, это не может работать, потому что синтаксический анализ RFC 3339 с использованиемstrptime невозможен. Строки формата, используемые модулем datetime в Python, не могут описать синтаксис RFC 3339.
Проблема в смещениях UTC. RFC 3339 Интернет - формат даты / времени требует , чтобы каждая дата-время включает в себя UTC смещение, и что эти смещения могут быть либо Z(сокращенно «Зулу времени») или в +HH:MMили -HH:MMформате, как +05:00и -10:30.
Следовательно, все они являются действительными датами времени RFC 3339:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Увы, строки формата используются strptimeи не strftimeимеют директив, соответствующих смещениям UTC в формате RFC 3339. Полный список директив, которые они поддерживают, можно найти по адресу https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior , и единственная директива смещения UTC, включенная в список %z:
% г
Смещение UTC в форме + ЧЧММ или -ЧЧММ (пустая строка, если объект наивный).
Пример: (пусто), +0000, -0400, +1030
Это не соответствует формату смещения RFC 3339, и действительно, если мы попытаемся использовать %zв строке формата и проанализировать дату RFC 3339, у нас не получится:
>>> from datetime import datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
Несколько ответов здесь, которые рекомендуют strptimeвсем обойти это, путем включения литерала Zв их строку формата, которая совпадает Zсо строкой даты и времени из примера автора вопроса (и отбрасывает ее, создаваяdatetime объект без часового пояса):
Поскольку при этом отбрасывается информация о часовом поясе, которая была включена в исходную строку даты и времени, сомнительно, должны ли мы рассматривать даже этот результат как правильный. Но что более важно, потому что этот подход включает в себя жесткое кодирование определенного смещения UTC в строку формата , он будет подавлен в тот момент, когда попытается проанализировать дату / время RFC 3339 с другим смещением UTC:
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%fZ")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'
Если вы не уверены, что вам нужно только поддерживать время RFC 3339 по времени Зулу, а не время с другими смещениями часового пояса, не используйте strptime. Вместо этого используйте один из многих других подходов, описанных в ответах.
Сногсшибательно, почему strptime не имеет директивы для информации о часовом поясе в формате ISO и почему его нельзя проанализировать. Невероятный.
Чаба Тот
2
@CsabaToth Полностью согласен - если у меня будет время, чтобы убить, возможно, я попытаюсь добавить его в язык. Или вы могли бы сделать это, если бы вы были так склонны - я вижу, у вас есть некоторый опыт C, в отличие от меня.
Марк Эмери
1
@ CsabaToth - Почему невероятно? Это работает достаточно хорошо для большинства людей, или они нашли достаточно легкий обходной путь. Если вам нужна функция, это с открытым исходным кодом, и вы можете добавить ее. Или заплатите кому-нибудь, чтобы сделать это для вас. Почему кто-то должен добровольно посвятить свое свободное время решению ваших конкретных проблем? Пусть источник будет с вами.
Питер М. - выступает за Монику
2
@PeterMasiar Невероятно, потому что обычно обнаруживается, что вещи в Python реализованы вдумчиво и полностью. Мы были испорчены этим вниманием к деталям, и поэтому, когда мы натыкаемся на что-то на языке, который «не пифоничен», мы выбрасываем наши игрушки из коляски, как я собираюсь сделать это прямо сейчас. Whaaaaaaaaaa Whaa wahaaaaa :-(
Робиньо
2
strptime()в Python 3.7 теперь поддерживает все, что описано как невозможное в этом ответе (буквально 'Z' и ':' в смещении часового пояса). К сожалению, есть еще один угловой случай, который делает RFC 3339 принципиально несовместимым с ISO 8601, а именно первый допускает отрицательное нулевое смещение часового пояса -00: 00, а последний нет.
СергейКолесников
75
Попробуйте модуль iso8601 ; это делает именно это.
Есть несколько других вариантов , упомянутых на WorkingWithTime странице на python.org вики.
Просто какiso8601.parse_date("2008-09-03T20:56:35.450686Z")
Пакман
3
Вопрос был не «как мне разобрать даты ISO 8601», а «как мне разобрать этот точный формат даты».
Николас Райли
3
@tiktak ОП спросил: «Мне нужно разобрать строки, такие как X», и мой ответ на это, попробовав обе библиотеки, состоит в том, чтобы использовать другую, потому что у iso8601 все еще остаются важные проблемы. Мое участие или отсутствие такового в таком проекте совершенно не связано с ответом.
Tobia
2
Имейте в виду, что версия iso8601 в пипсах не обновлялась с 2007 года, и в ней есть некоторые серьезные ошибки. Я рекомендую применить некоторые критические исправления самостоятельно или найти одну из многих вилок github, которые уже сделали это github.com/keithhackbarth/pyiso8601-strict
keithhackbarth
6
iso8601 , также известный как pyiso8601 , был обновлен совсем недавно, в феврале 2014 года. Последняя версия поддерживает гораздо более широкий набор строк ISO 8601. Я использовал с хорошим эффектом в некоторых из моих проектов.
Дейв Хейн
34
импорт ре, дата и время
s = "2008-09-03T20: 56: 35.450686Z"
d = datetime.datetime (* map (int, re.split ('[^ \ d]', s) [: - 1]))
Я не согласен, это практически нечитаемо, и, насколько я могу судить, не учитывает Zulu (Z), который делает эту дату-время наивной, даже если были предоставлены данные часового пояса.
Umbrae
14
Я нахожу это вполне читабельным. На самом деле, это, вероятно, самый простой и эффективный способ преобразования без установки дополнительных пакетов.
Тобиа
2
Это эквивалентно d = datetime.datetime (* map (int, re.split ('\ D', s) [: - 1])) я полагаю.
Это приводит к наивному объекту datetime без часового пояса, верно? Таким образом, бит UTC теряется в переводе?
w00t
32
Какую именно ошибку вы получаете? Это похоже на следующее?
>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z","%Y-%m-%dT%H:%M:%S.Z")ValueError: time data did not match format: data=2008-08-12T12:20:30.656234Z fmt=%Y-%m-%dT%H:%M:%S.Z
Если да, вы можете разделить вашу входную строку на «.», А затем добавить микросекунды к полученному времени.
Вы не можете просто раздеться .Z, потому что это означает часовой пояс и может быть другим. Мне нужно преобразовать дату в часовой пояс UTC.
Александр Артеменко
Простой объект даты и времени не имеет понятия часового пояса. Если все ваши времена заканчиваются на «Z», все получаемые вами даты - UTC (время Зулу).
tzot
если часовой пояс отличается от ""или "Z", то это должно быть смещение в часах / минутах, которое может быть непосредственно добавлено / вычтено из объекта datetime. Вы могли бы создать подкласс tzinfo, чтобы справиться с этим, но это, вероятно, не рекомендуется.
SingleNegationElimination
8
Кроме того, "% f" - это спецификатор микросекунды, поэтому строка strptime (без часовых поясов) выглядит следующим образом: "% Y-% m-% dT% H:% M:% S.% f".
quodlibetor
1
Это вызовет исключение, если заданная строка даты и времени имеет смещение UTC, отличное от «Z». Он не поддерживает весь формат RFC 3339 и является неполноценным ответом для других, которые правильно обрабатывают смещения UTC.
Марк Амери
25
Начиная с Python 3.7, strptime поддерживает разделители двоеточий в смещениях UTC ( источник ). Таким образом, вы можете использовать:
Но в 3.7, вы также имеете datetime.fromisoformat()какие ручки строки , как автоматически ваш вход: datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00').
Мартин Питерс
2
Хорошая точка зрения. Я согласен, я рекомендую использовать datetime.fromisoformat()иdatetime.isoformat()
Andreas Profous
19
В наши дни Arrow также можно использовать как стороннее решение:
>>>import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")>>> date.datetime
datetime.datetime(2008,9,3,20,56,35,450686, tzinfo=tzutc())
Просто используйте python-dateutil - стрелка требует python-dateutil.
Данизен
Стрелка теперь поддерживает ISO8601. Упомянутые проблемы сейчас закрыты.
Altus
18
Просто используйте python-dateutilмодуль:
>>>import dateutil.parser as dp
>>> t ='1984-06-02T19:05:00.000Z'>>>parsed_t= dp.parse(t)>>>print(parsed_t)
datetime.datetime(1984,6,2,19,5, tzinfo=tzutc())
@tripleee На самом деле я только что проверил код, и он, кажется, возвращает правильный ответ: 455051100(проверено на epochconverter.com ) ,,, разве я что-то упустил?
Blairg23
13
Если вы не хотите использовать dateutil, вы можете попробовать эту функцию:
def from_utc(utcTime,fmt="%Y-%m-%dT%H:%M:%S.%fZ"):"""
Convert UTC time string to time.struct_time
"""# change datetime.datetime to time, return time.struct_time typereturn datetime.datetime.strptime(utcTime, fmt)
Этот ответ основан на жестком кодировании определенного смещения UTC (а именно «Z», что означает +00: 00) в строку формата, переданную в strptime. Это плохая идея, потому что она не сможет проанализировать любое время и дату с другим смещением UTC и вызвать исключение. Посмотрите мой ответ, который описывает, как на самом деле невозможно проанализировать RFC 3339 с помощью strptime.
Марк Амери
1
Он жестко запрограммирован, но его достаточно для случая, когда нужно разобрать только зулу.
Саша
1
@alexander yes - это может иметь место, если, например, вы знаете, что ваша строка даты была сгенерирована toISOStringметодом JavaScript . Но в этом ответе нет упоминания об ограничении дат времени зулусов, и при этом вопрос не указывает, что это все, что нужно, и простое использование dateutilобычно одинаково удобно и менее узко в том, что он может анализировать.
Марк Амери
11
Если вы работаете с Django, он предоставляет модуль dateparse, который принимает множество форматов, похожих на формат ISO, включая часовой пояс.
Если вы не используете Django и не хотите использовать одну из других библиотек, упомянутых здесь, вы, вероятно, можете адаптировать исходный код Django для dateparse для вашего проекта.
Это похоже на отличную библиотеку! К сожалению, для тех, кто хочет оптимизировать синтаксический анализ ISO8601 в Google App Engine, мы не можем его использовать, поскольку это библиотека C, но ваши тесты были полезны, чтобы показать, что native datetime.strptime()является следующим самым быстрым решением. Спасибо, что собрали всю эту информацию!
hamx0r
3
@ hamx0r, учтите, что datetime.strptime()это не полная библиотека синтаксического анализа ISO 8601. Если вы используете Python 3.7, вы можете использовать datetime.fromisoformat()метод, который немного более гибкий. Возможно, вас заинтересует этот более полный список парсеров, который вскоре должен быть объединен с README ciso8601.
movermeyer
ciso8601 работает довольно хорошо, но сначала нужно выполнить «pip install pytz», потому что невозможно проанализировать метку времени с информацией о часовом поясе без зависимости pytz. Пример будет выглядеть так: dob = ciso8601.parse_datetime (result ['dob'] ['date'])
Этот ответ основан на жестком кодировании определенного смещения UTC (а именно «Z», что означает +00: 00) в строку формата, переданную в strptime. Это плохая идея, потому что она не сможет проанализировать любое время и дату с другим смещением UTC и вызвать исключение. Посмотрите мой ответ, который описывает, как на самом деле невозможно проанализировать RFC 3339 с помощью strptime.
Марк Амери
1
В теории да, это не удается. На практике я никогда не встречал дату в формате ISO 8601, которая была не во время зулу. Для моей очень редкой потребности это прекрасно работает и не зависит от какой-либо внешней библиотеки.
Бенджамин Риггс
4
Вы могли бы использовать timezone.utcвместо timezone(timedelta(0)). Кроме того, код работает в Python 2.6+ (по крайней мере), если вы предоставляете utcобъект tzinfo
jfs
Не имеет значения, если вы столкнулись с этим, это не соответствует спецификации.
thennouncer
Вы можете использовать %Zдля часового пояса в самых последних версиях Python.
Свентечие
7
Я автор утилит iso8601. Его можно найти на GitHub или PyPI . Вот как вы можете разобрать свой пример:
Одним простым способом преобразования строки даты, подобной ISO 8601, в метку времени UNIX или datetime.datetimeобъект во всех поддерживаемых версиях Python без установки сторонних модулей является использование анализатора даты SQLite .
#!/usr/bin/env pythonfrom __future__ import with_statement, division, print_function
import sqlite3
import datetime
testtimes =["2016-08-25T16:01:26.123456Z","2016-08-25T16:01:29",]
db = sqlite3.connect(":memory:")
c = db.cursor()for timestring in testtimes:
c.execute("SELECT strftime('%s', ?)",(timestring,))
converted = c.fetchone()[0]print("%s is %s after epoch"%(timestring, converted))
dt = datetime.datetime.fromtimestamp(int(converted))print("datetime is %s"% dt)
Вывод:
2016-08-25T16:01:26.123456Zis1472140886 after epoch
datetime is2016-08-2512:01:262016-08-25T16:01:29is1472140889 after epoch
datetime is2016-08-2512:01:29
Какой невероятный, удивительный, красивый взлом! Спасибо!
Havok
6
Я написал парсер для стандарта ISO 8601 и разместил его на GitHub: https://github.com/boxed/iso8601 . Эта реализация поддерживает все в спецификации, кроме длительностей, интервалов, периодических интервалов и дат вне поддерживаемого диапазона дат модуля Python datetime.
Потому что ISO 8601 допускает множество вариаций необязательных двоеточий и тире CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. Если вы хотите использовать strptime, вы должны сначала удалить эти варианты.
Цель состоит в том, чтобы сгенерировать объект utc datetime.
Если вам нужен базовый случай, который работает для UTC с суффиксом Z, например 2016-06-29T19:36:29.3453Z:
Если вы хотите обрабатывать смещения часового пояса, например 2016-06-29T19:36:29.3453-0400или 2008-09-03T20:56:35.450686+05:00используйте следующее. Они преобразуют все варианты во что-то без разделителей переменных, например, 20080903T205635.450686+0500делая его более согласованным / более простым для анализа.
import re
# this regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))",'', timestamp)
datetime.datetime.strptime(conformed_timestamp,"%Y%m%dT%H%M%S.%f%z")
Если ваша система не поддерживает %zдирективу strptime (вы видите что-то подобное ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'), вам нужно вручную сместить время от Z(UTC). Примечание %zможет не работать в вашей системе в версиях Python <3, поскольку это зависит от поддержки библиотеки c, которая варьируется в зависимости от типа сборки системы / python (например, Jython, Cython и т. Д.).
import re
import datetime
# this regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))",'', timestamp)# split on the offset to remove it. use a capture group to keep the delimiter
split_timestamp = re.split(r"[+|-]",conformed_timestamp)
main_timestamp = split_timestamp[0]if len(split_timestamp)==3:
sign = split_timestamp[1]
offset = split_timestamp[2]else:
sign =None
offset =None# generate the datetime object without the offset at UTC time
output_datetime = datetime.datetime.strptime(main_timestamp +"Z","%Y%m%dT%H%M%S.%fZ")if offset:# create timedelta based on offset
offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:]))# offset datetime with timedelta
output_datetime = output_datetime + offset_delta
Благодаря ответу великого Марка Эмери я разработал функцию учета всех возможных форматов ISO даты и времени:
classFixedOffset(tzinfo):"""Fixed offset in minutes: `time = utc_time + utc_offset`."""def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset,60)#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones# that have the opposite sign in the name;# the corresponding numeric value is not used e.g., no minutes
self.__name ='<%+03d%02d>%+d'%(hours, minutes,-hours)def utcoffset(self, dt=None):return self.__offset
def tzname(self, dt=None):return self.__name
def dst(self, dt=None):return timedelta(0)def __repr__(self):return'FixedOffset(%d)'%(self.utcoffset().total_seconds()/60)def __getinitargs__(self):return(self.__offset.total_seconds()/60,)def parse_isoformat_datetime(isodatetime):try:return datetime.strptime(isodatetime,'%Y-%m-%dT%H:%M:%S.%f')exceptValueError:passtry:return datetime.strptime(isodatetime,'%Y-%m-%dT%H:%M:%S')exceptValueError:pass
pat = r'(.*?[+-]\d{2}):(\d{2})'
temp = re.sub(pat, r'\1\2', isodatetime)
naive_date_str = temp[:-5]
offset_str = temp[-5:]
naive_dt = datetime.strptime(naive_date_str,'%Y-%m-%dT%H:%M:%S.%f')
offset = int(offset_str[-4:-2])*60+ int(offset_str[-2:])if offset_str[0]=="-":
offset =-offset
return naive_dt.replace(tzinfo=FixedOffset(offset))
Ответы:
Пакет python-dateutil может анализировать не только строки даты и времени RFC 3339, как в вопросе, но также и другие строки даты и времени ISO 8601, которые не соответствуют RFC 3339 (например, те, которые не имеют смещения UTC, или те, которые представляют только свидание).
Обратите внимание, что
dateutil.parser.isoparse
предположительно строже, чем более хакерскийdateutil.parser.parse
, но оба они довольно просты и попытаются интерпретировать передаваемую вами строку. Если вы хотите исключить возможность каких-либо неправильных прочтений, вам нужно использовать что-то более строгое, чем любой из этих функции.Имя Pypi
python-dateutil
неdateutil
(спасибо code3monk3y ):Если вы используете Python 3.7, взглянуть на этот ответ о
datetime.datetime.fromisoformat
.источник
python-dateutil
неdateutil
так:pip install python-dateutil
.dateutil.parser
он намеренно взломан: он пытается угадать формат и делает неизбежные предположения (настраиваемые только вручную) в неоднозначных случаях. Так что используйте его ТОЛЬКО, если вам нужно разобрать ввод неизвестного формата, и вы можете терпеть случайные неправильные чтения.Новое в Python 3.7+
В
datetime
стандартной библиотеке появилась функция инвертированияdatetime.isoformat()
.Пример использования:
источник
datetime
может содержать atzinfo
и, следовательно, выводить часовой пояс, ноdatetime.fromisoformat()
не анализирует tzinfo? похоже на ошибку ..isoformat
. Он не принимает пример в вопросе"2008-09-03T20:56:35.450686Z"
из-за трейлингаZ
, но он принимает"2008-09-03T20:56:35.450686"
.Z
входной скрипт можно изменить с помощьюdate_string.replace("Z", "+00:00")
.Обратите внимание, что в Python 2.6+ и Py3K символ% f перехватывает микросекунды.
Смотрите проблему здесь
источник
strptime
на самом деле невозможно выполнить разбор RFC 3339 .datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
так чтоНесколько ответов здесь предлагают использовать
datetime.datetime.strptime
для анализа времени RFC 3339 или ISO 8601 с часовыми поясами, как показано в вопросе:Это плохая идея.
Предполагая, что вы хотите поддерживать полный формат RFC 3339, включая поддержку смещений UTC, отличных от нуля, код, предлагаемый этими ответами, не работает. Действительно, это не может работать, потому что синтаксический анализ RFC 3339 с использованием
strptime
невозможен. Строки формата, используемые модулем datetime в Python, не могут описать синтаксис RFC 3339.Проблема в смещениях UTC. RFC 3339 Интернет - формат даты / времени требует , чтобы каждая дата-время включает в себя UTC смещение, и что эти смещения могут быть либо
Z
(сокращенно «Зулу времени») или в+HH:MM
или-HH:MM
формате, как+05:00
и-10:30
.Следовательно, все они являются действительными датами времени RFC 3339:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Увы, строки формата используются
strptime
и неstrftime
имеют директив, соответствующих смещениям UTC в формате RFC 3339. Полный список директив, которые они поддерживают, можно найти по адресу https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior , и единственная директива смещения UTC, включенная в список%z
:Это не соответствует формату смещения RFC 3339, и действительно, если мы попытаемся использовать
%z
в строке формата и проанализировать дату RFC 3339, у нас не получится:(На самом деле, вышесказанное - это то, что вы увидите в Python 3. В Python 2 мы потерпим неудачу по еще более простой причине, заключающейся в том, что в Python 2 директива
strptime
вообще не реализуется.%z
)Несколько ответов здесь, которые рекомендуют
strptime
всем обойти это, путем включения литералаZ
в их строку формата, которая совпадаетZ
со строкой даты и времени из примера автора вопроса (и отбрасывает ее, создаваяdatetime
объект без часового пояса):Поскольку при этом отбрасывается информация о часовом поясе, которая была включена в исходную строку даты и времени, сомнительно, должны ли мы рассматривать даже этот результат как правильный. Но что более важно, потому что этот подход включает в себя жесткое кодирование определенного смещения UTC в строку формата , он будет подавлен в тот момент, когда попытается проанализировать дату / время RFC 3339 с другим смещением UTC:
Если вы не уверены, что вам нужно только поддерживать время RFC 3339 по времени Зулу, а не время с другими смещениями часового пояса, не используйте
strptime
. Вместо этого используйте один из многих других подходов, описанных в ответах.источник
strptime()
в Python 3.7 теперь поддерживает все, что описано как невозможное в этом ответе (буквально 'Z' и ':' в смещении часового пояса). К сожалению, есть еще один угловой случай, который делает RFC 3339 принципиально несовместимым с ISO 8601, а именно первый допускает отрицательное нулевое смещение часового пояса -00: 00, а последний нет.Попробуйте модуль iso8601 ; это делает именно это.
Есть несколько других вариантов , упомянутых на WorkingWithTime странице на python.org вики.
источник
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
источник
datetime.datetime(*map(int, re.findall('\d+', s))
Какую именно ошибку вы получаете? Это похоже на следующее?
Если да, вы можете разделить вашу входную строку на «.», А затем добавить микросекунды к полученному времени.
Попробуй это:
источник
""
или"Z"
, то это должно быть смещение в часах / минутах, которое может быть непосредственно добавлено / вычтено из объекта datetime. Вы могли бы создать подкласс tzinfo, чтобы справиться с этим, но это, вероятно, не рекомендуется.Начиная с Python 3.7, strptime поддерживает разделители двоеточий в смещениях UTC ( источник ). Таким образом, вы можете использовать:
РЕДАКТИРОВАТЬ:
Как отметил Мартин, если вы создали объект datetime с помощью isoformat (), вы можете просто использовать datetime.fromisoformat ()
источник
datetime.fromisoformat()
какие ручки строки , как автоматически ваш вход:datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00')
.datetime.fromisoformat()
иdatetime.isoformat()
В наши дни Arrow также можно использовать как стороннее решение:
источник
Просто используйте
python-dateutil
модуль:Документация
источник
455051100
(проверено на epochconverter.com ) ,,, разве я что-то упустил?Если вы не хотите использовать dateutil, вы можете попробовать эту функцию:
Тестовое задание:
Результат:
источник
strptime
. Это плохая идея, потому что она не сможет проанализировать любое время и дату с другим смещением UTC и вызвать исключение. Посмотрите мой ответ, который описывает, как на самом деле невозможно проанализировать RFC 3339 с помощью strptime.toISOString
методом JavaScript . Но в этом ответе нет упоминания об ограничении дат времени зулусов, и при этом вопрос не указывает, что это все, что нужно, и простое использованиеdateutil
обычно одинаково удобно и менее узко в том, что он может анализировать.Если вы работаете с Django, он предоставляет модуль dateparse, который принимает множество форматов, похожих на формат ISO, включая часовой пояс.
Если вы не используете Django и не хотите использовать одну из других библиотек, упомянутых здесь, вы, вероятно, можете адаптировать исходный код Django для dateparse для вашего проекта.
источник
DateTimeField
использует это, когда вы устанавливаете строковое значение.Я обнаружил, что ciso8601 - это самый быстрый способ анализа временных меток ISO 8601. Как следует из названия, он реализован на C.
GitHub Repo README показывает их> 10x ускорение по отношению ко всем другим библиотекам , перечисленных в других ответах.
Мой личный проект включал много разбора ISO 8601. Было приятно иметь возможность просто переключать вызов и идти в 10 раз быстрее. :)
Изменить: с тех пор я стал сопровождающим ciso8601. Теперь быстрее, чем когда-либо!
источник
datetime.strptime()
является следующим самым быстрым решением. Спасибо, что собрали всю эту информацию!datetime.strptime()
это не полная библиотека синтаксического анализа ISO 8601. Если вы используете Python 3.7, вы можете использоватьdatetime.fromisoformat()
метод, который немного более гибкий. Возможно, вас заинтересует этот более полный список парсеров, который вскоре должен быть объединен с README ciso8601.Это работает для stdlib на Python 3.2 и более поздних версиях (при условии, что все метки времени указаны в формате UTC):
Например,
источник
strptime
. Это плохая идея, потому что она не сможет проанализировать любое время и дату с другим смещением UTC и вызвать исключение. Посмотрите мой ответ, который описывает, как на самом деле невозможно проанализировать RFC 3339 с помощью strptime.timezone.utc
вместоtimezone(timedelta(0))
. Кроме того, код работает в Python 2.6+ (по крайней мере), если вы предоставляетеutc
объект tzinfo%Z
для часового пояса в самых последних версиях Python.Я автор утилит iso8601. Его можно найти на GitHub или PyPI . Вот как вы можете разобрать свой пример:
источник
Одним простым способом преобразования строки даты, подобной ISO 8601, в метку времени UNIX или
datetime.datetime
объект во всех поддерживаемых версиях Python без установки сторонних модулей является использование анализатора даты SQLite .Вывод:
источник
Я написал парсер для стандарта ISO 8601 и разместил его на GitHub: https://github.com/boxed/iso8601 . Эта реализация поддерживает все в спецификации, кроме длительностей, интервалов, периодических интервалов и дат вне поддерживаемого диапазона дат модуля Python datetime.
Тесты включены! :П
источник
Функция parse_datetime () в Django поддерживает даты со смещением UTC:
Таким образом, его можно использовать для анализа дат ISO 8601 в полях всего проекта:
источник
Потому что ISO 8601 допускает множество вариаций необязательных двоеточий и тире
CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
. Если вы хотите использовать strptime, вы должны сначала удалить эти варианты.Цель состоит в том, чтобы сгенерировать объект utc datetime.
Если вам нужен базовый случай, который работает для UTC с суффиксом Z, например
2016-06-29T19:36:29.3453Z
:Если вы хотите обрабатывать смещения часового пояса, например
2016-06-29T19:36:29.3453-0400
или2008-09-03T20:56:35.450686+05:00
используйте следующее. Они преобразуют все варианты во что-то без разделителей переменных, например,20080903T205635.450686+0500
делая его более согласованным / более простым для анализа.Если ваша система не поддерживает
%z
директиву strptime (вы видите что-то подобноеValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
), вам нужно вручную сместить время отZ
(UTC). Примечание%z
может не работать в вашей системе в версиях Python <3, поскольку это зависит от поддержки библиотеки c, которая варьируется в зависимости от типа сборки системы / python (например, Jython, Cython и т. Д.).источник
Для чего-то, что работает со стандартной библиотекой 2.X, попробуйте:
calendar.timegm - это отсутствующая версия gm time.mktime.
источник
Python-dateutil будет генерировать исключение при разборе недопустимых строк даты, поэтому вы можете захотеть перехватить исключение.
источник
В настоящее время существует Maya: Datetimes for Humans ™ , от автора популярного пакета Requests: HTTP for Humans ™:
источник
Другой способ заключается в использовании специализированного парсер для ISO-8601 является использование isoparse функции dateutil парсер:
Вывод:
Эта функция также упоминается в документации для стандартной функции Python datetime.fromisoformat :
источник
Благодаря ответу великого Марка Эмери я разработал функцию учета всех возможных форматов ISO даты и времени:
источник
Обратите внимание, что мы должны посмотреть, если строка не заканчивается
Z
, мы могли бы проанализировать с помощью%z
.источник
Первоначально я пытался с:
Но это не сработало на отрицательных часовых поясах. Это, однако, я работал нормально, в Python 3.7.3:
Некоторые тесты отмечают, что выход отличается только точностью микросекунд. Получил 6 цифр точности на моей машине, но YMMV:
источник
frozenset(('+', '-'))
? Разве обычный кортеж не('+', '-')
должен быть в состоянии выполнить то же самое?