Как перевести строку ISO 8601 datetime в объект Python datetime? [дубликат]
этот вопрос уже есть ответ здесь:
как разобрать дату в формате ISO 8601?
24 ответов
Я получаю строку datetime в формате "2009-05-28T16:15: 00" (это ISO 8601, я считаю) один вариант hack-ish, похоже, разбирает строку с помощью time.strptime и передача первых 6 элементов чтобы войти в конструктор datetime, например:
datetime.datetime(*time.strptime("2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S")[:6])
Я не смог найти "чистый" способ сделать это, есть один?
11 ответов:
Я предпочитаю использовать dateutil библиотека для обработки часового пояса и, как правило, сплошной разбор даты. Если бы вы получили строку ISO 8601, такую как:2010-05-08T23:41: 54.000 Z, вы бы весело провели время, анализируя это с помощью strptime, особенно если вы не знали заранее, включен ли часовой пояс. pyiso8601 имеет несколько проблем (проверьте их трекер), с которыми я столкнулся во время моего использования, и он не обновлялся в течение нескольких лет. dateutil, напротив, был активен и работал для меня:
import dateutil.parser yourdate = dateutil.parser.parse(datestring)
потому что ISO 8601 позволяет много вариантов дополнительных двоеточий и тире присутствует, в основном
CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. Если вы хотите использовать strptime, вам нужно сначала удалить эти варианты.
цель состоит в том, чтобы создать объект utc datetime.
Если вам просто нужен базовый случай, который работает для UTC с суффиксом Z, например2016-06-29T19:36:29.3453Z:datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ")
Если вы хотите обрабатывать смещения часового пояса как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может не работать в вашей системе в версиях pythonimport 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
стрелка выглядит многообещающе для этого:
>>> import arrow >>> arrow.get('2014-11-13T14:53:18.694072+00:00').datetime datetime.datetime(2014, 11, 13, 14, 53, 18, 694072, tzinfo=tzoffset(None, 0))Arrow-это библиотека Python, которая обеспечивает разумный, интеллектуальный способ создания, управления, форматирования и преобразования дат и времени. Стрелка проста, легка и сильно вдохновлена момент.js и запросы.
вы должны следить за информацией о часовом поясе, так как вы можете попасть в беду при сравнении не-TZ-aware datetimes с TZ-aware.
вероятно, лучше всего всегда делать их TZ-aware (даже если только как utc), если вы действительно не знаете, почему это было бы бесполезно.
#----------------------------------------------- import datetime import pytz import dateutil.parser #----------------------------------------------- utc = pytz.utc BERLIN = pytz.timezone('Europe/Berlin') #----------------------------------------------- def to_iso8601(when=None, tz=BERLIN): if not when: when = datetime.datetime.now(tz) if not when.tzinfo: when = tz.localize(when) _when = when.strftime("%Y-%m-%dT%H:%M:%S.%f%z") return _when[:-8] + _when[-5:] # remove microseconds #----------------------------------------------- def from_iso8601(when=None, tz=BERLIN): _when = dateutil.parser.parse(when) if not _when.tzinfo: _when = tz.localize(_when) return _when #-----------------------------------------------
Я еще не пробовал, но pyiso8601 обещает поддержать это.
import datetime, time def convert_enddate_to_seconds(self, ts): """Takes ISO 8601 format(string) and converts into epoch time.""" dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1') seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0 return secondsЭто также включает в себя миллисекунды и часовой пояс.
Если время '2012-09-30T15:31:50.262-08:00', это превратится в эпоху времени.
>>> import datetime, time >>> ts = '2012-09-30T15:31:50.262-08:00' >>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1') >>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0 >>> seconds 1348990310.26
Isodate Кажется, есть наиболее полная поддержка.
в обоих направлениях:
эпоха к времени ISO:
isoTime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(epochTime))время ISO к эпохе:
epochTime = time.mktime(time.strptime(isoTime, '%Y-%m-%dT%H:%M:%SZ'))
aniso8601 должны справиться с этим. Он также понимает часовые пояса, python2 и python3, и имеет разумное покрытие остальной части в формате iso8601 Если вы когда-нибудь понадобится.
import aniso8601 aniso8601.parse_datetime('2007-03-04T21:08:12')
вот ужин простой способ сделать такие преобразования. Нет разбора, или дополнительные библиотеки не требуется. Чистый, простой и быстрый.
import datetime import time ################################################ # # Takes the time (in seconds), # and returns a string of the time in ISO8601 format. # Note: Timezone is UTC # ################################################ def TimeToISO8601(seconds): strKv = datetime.datetime.fromtimestamp(seconds).strftime('%Y-%m-%d') strKv = strKv + "T" strKv = strKv + datetime.datetime.fromtimestamp(seconds).strftime('%H:%M:%S') strKv = strKv +"Z" return strKv ################################################ # # Takes a string of the time in ISO8601 format, # and returns the time (in seconds). # Note: Timezone is UTC # ################################################ def ISO8601ToTime(strISOTime): K1 = 0 K2 = 9999999999 K3 = 0 counter = 0 while counter < 95: K3 = (K1 + K2) / 2 strK4 = TimeToISO8601(K3) if strK4 < strISOTime: K1 = K3 if strK4 > strISOTime: K2 = K3 counter = counter + 1 return K3 ################################################ # # Takes a string of the time in ISO8601 (UTC) format, # and returns a python DateTime object. # Note: returned value is your local time zone. # ################################################ def ISO8601ToDateTime(strISOTime): return time.gmtime(ISO8601ToTime(strISOTime)) #To test: Test = "2014-09-27T12:05:06.9876" print ("The test value is: " + Test) Ans = ISO8601ToTime(Test) print ("The answer in seconds is: " + str(Ans)) print ("And a Python datetime object is: " + str(ISO8601ToDateTime(Test)))
Comments