복붙노트

[PYTHON] ISO 8601 형식의 날짜를 어떻게 파싱합니까?

PYTHON

ISO 8601 형식의 날짜를 어떻게 파싱합니까?

"2008-09-03T20 : 56 : 35.450686Z"와 같은 RFC 3339 문자열을 파이썬의 datetime 형식으로 구문 분석해야합니다.

나는 파이썬 표준 라이브러리에서 strptime을 발견했지만 매우 편리하지는 않다.

이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

해결법

  1. ==============================

    1.python-dateutil 패키지는 질문에있는 것과 같은 RFC 3339 datetime 문자열뿐만 아니라 RFC 3339를 준수하지 않는 다른 ISO 8601 날짜 및 시간 문자열 (UTC 오프셋이없는 문자열 또는 나타내는 것과 같은)도 구문 분석 할 수 있습니다 날짜 만).

    python-dateutil 패키지는 질문에있는 것과 같은 RFC 3339 datetime 문자열뿐만 아니라 RFC 3339를 준수하지 않는 다른 ISO 8601 날짜 및 시간 문자열 (UTC 오프셋이없는 문자열 또는 나타내는 것과 같은)도 구문 분석 할 수 있습니다 날짜 만).

    >>> import dateutil.parser
    >>> dateutil.parser.parse('2008-09-03T20:56:35.450686Z') # RFC 3339 format
    datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
    >>> dateutil.parser.parse('2008-09-03T20:56:35.450686') # ISO 8601 extended format
    datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
    >>> dateutil.parser.parse('20080903T205635.450686') # ISO 8601 basic format
    datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
    >>> dateutil.parser.parse('20080903') # ISO 8601 basic format, date only
    datetime.datetime(2008, 9, 3, 0, 0)
    

    dateutil.parser는 의도적으로 해키입니다. 형식을 추측하고 모호한 경우에 필연적 인 가정 (손으로 만 사용자 정의 가능)을 시도합니다. 알 수없는 형식의 입력을 구문 분석해야하는 경우에만 사용하고 가끔 오판을 용인해도 좋습니다. (고맙습니다 ivan_pozdeev)

    Pypi 이름은 python-dateutil이며 dateutil은 아닙니다 (thanks code3monk3y) :

    pip install python-dateutil
    

    Python 3.7을 사용하고 있다면 datetime.datetime.fromisoformat에 대한 답을 살펴보십시오.

  2. ==============================

    2.Python 2.6+ 및 Py3K에서 % f 문자는 마이크로 초를 포착합니다.

    Python 2.6+ 및 Py3K에서 % f 문자는 마이크로 초를 포착합니다.

    >>> datetime.datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
    

    여기에서 문제를 참조하십시오.

  3. ==============================

    3.몇 가지 답변은 datetime.datetime.strptime을 사용하여 RFC 3339 또는 ISO 8601 datetimes를 시간대와 함께 파싱하는 것이 좋습니다. 예를 들면 다음과 같습니다.

    몇 가지 답변은 datetime.datetime.strptime을 사용하여 RFC 3339 또는 ISO 8601 datetimes를 시간대와 함께 파싱하는 것이 좋습니다. 예를 들면 다음과 같습니다.

    2008-09-03T20:56:35.450686Z
    

    이것은 나쁜 생각입니다.

    0이 아닌 UTC 오프셋에 대한 지원을 포함하여 전체 RFC 3339 형식을 지원한다고 가정하면 이러한 대답이 제안하는 코드는 작동하지 않습니다. 실제로 strptime을 사용하는 RFC 3339 구문 구문 분석은 불가능하기 때문에 작동하지 않습니다. 파이썬의 datetime 모듈이 사용하는 형식 문자열은 RFC 3339 구문을 설명 할 수 없습니다.

    문제는 UTC 오프셋입니다. RFC 3339 인터넷 날짜 / 시간 형식에서는 모든 날짜 - 시간에 UTC 오프셋이 포함되어야하며 이러한 오프셋은 Z (Zulu 시간의 약자) 또는 + HH : MM 또는 -HH : MM 형식 (예 : + 05:00 또는 -10:30.

    결과적으로 다음은 모두 유효한 RFC 3339 날짜입니다.

    아아, strptime 및 strftime에 사용되는 형식 문자열에는 RFC 3339 형식의 UTC 오프셋에 해당하는 지시문이 없습니다. 지원하는 명령의 전체 목록은 https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior에서 찾을 수 있으며 목록에 포함 된 유일한 UTC 오프셋 지시문은 % 지:

    이것은 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")
  4. ==============================

    4.iso8601 모듈을 사용해보십시오. 그것은 정확하게 이것을합니다.

    iso8601 모듈을 사용해보십시오. 그것은 정확하게 이것을합니다.

    python.org wiki의 WorkingWithTime 페이지에 언급 된 몇 가지 다른 옵션이 있습니다.

  5. ==============================

    5.

    import re,datetime
    s="2008-09-03T20:56:35.450686Z"
    d=datetime.datetime(*map(int, re.split('[^\d]', s)[:-1]))
    
  6. ==============================

    6.datetime 표준 라이브러리는 datetime.isoformat ()을 반전하는 함수를 도입했습니다.

    datetime 표준 라이브러리는 datetime.isoformat ()을 반전하는 함수를 도입했습니다.

    사용 예 :

    from datetime import datetime
    
    date = datetime.fromisoformat('2017-01-01T12:30:59.000000')
    
  7. ==============================

    7.당신이 얻는 정확한 오류는 무엇입니까? 다음과 같은가요?

    당신이 얻는 정확한 오류는 무엇입니까? 다음과 같은가요?

    >>> 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
    

    그렇다면 입력 문자열을 "."로 나눈 다음 마이크로 초를 추가 한 datetime에 추가 할 수 있습니다.

    이 시도:

    >>> def gt(dt_str):
            dt, _, us= dt_str.partition(".")
            dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
            us= int(us.rstrip("Z"), 10)
            return dt + datetime.timedelta(microseconds=us)
    
    >>> gt("2008-08-12T12:20:30.656234Z")
    datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
    
  8. ==============================

    8.요즘 Arrow는 타사 솔루션으로도 사용할 수 있습니다.

    요즘 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())
    
  9. ==============================

    9.파이썬 3.7부터 strptime은 콜론 구분자를 UTC 오프셋 (소스)으로 지원합니다. 따라서 다음을 사용할 수 있습니다.

    파이썬 3.7부터 strptime은 콜론 구분자를 UTC 오프셋 (소스)으로 지원합니다. 따라서 다음을 사용할 수 있습니다.

    import datetime
    datetime.datetime.strptime('2018-01-31T09:24:31.488670+00:00', '%Y-%m-%dT%H:%M:%S.%f%z')
    
  10. ==============================

    10.dateutil을 사용하지 않으려는 경우이 함수를 사용해보십시오.

    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 type
        return datetime.datetime.strptime(utcTime, fmt)
    

    테스트:

    from_utc("2007-03-04T21:08:12.123Z")
    

    결과:

    datetime.datetime(2007, 3, 4, 21, 8, 12, 123000)
    
  11. ==============================

    11.Django로 작업하고 있다면, 표준 시간대를 포함하여 ISO 형식과 유사한 형식의 묶음을 허용하는 dateparse 모듈을 제공합니다.

    Django로 작업하고 있다면, 표준 시간대를 포함하여 ISO 형식과 유사한 형식의 묶음을 허용하는 dateparse 모듈을 제공합니다.

    Django를 사용하지 않고 여기에 언급 된 다른 라이브러리 중 하나를 사용하고 싶지 않다면 Django 소스 코드를 프로젝트에 적용 할 수 있습니다.

  12. ==============================

    12.모두가 만드는 것보다 훨씬 더 간단합니다.

    모두가 만드는 것보다 훨씬 더 간단합니다.

    epoch 이후 초를 얻으려면 python-dateutil을 사용하여 datetime 객체로 변환 한 다음 strftime 메소드를 사용하여 초 단위로 변환하십시오. 이렇게 :

    >>> import dateutil.parser as dp
    >>> t = '1984-06-02T19:05:00.000Z'
    >>> parsed_t = dp.parse(t)
    >>> t_in_seconds = parsed_t.strftime('%s')
    >>> t_in_seconds
    '455047500'
    

    출처

    주 : 주어진 datetime을 epoch 시간으로 변환합니다. 그러나 strftime () 함수를 사용하여 해당 날짜 시간을 모든 형식으로 변환 할 수 있습니다. 여기서 parsed_t 객체는이 시점에서 datetime 유형입니다.

  13. ==============================

    13.ciso8601이 ISO 8601 타임 스탬프를 구문 분석하는 가장 빠른 방법이라는 것을 알았습니다. 이름에서 알 수 있듯이 C로 구현됩니다.

    ciso8601이 ISO 8601 타임 스탬프를 구문 분석하는 가장 빠른 방법이라는 것을 알았습니다. 이름에서 알 수 있듯이 C로 구현됩니다.

    import ciso8601
    ciso8601.parse_datetime('2014-01-09T21:48:00.921000+05:30')
    

    GitHub Repo README는 다른 답변에 나열된 다른 모든 라이브러리와 비교하여 10 배 이상 빠른 속도를 보여줍니다.

    내 개인 프로젝트에는 ISO 8601 구문 분석이 많이 사용되었습니다. 전화를 전환하고 10 배 빠르게 할 수 있다는 것이 좋았습니다. :)

    편집 : 나는 이후 ciso8601의 관리자가되었습니다. 이제 그 어느 때보 다 빠릅니다!

  14. ==============================

    14.필자는 ISO 8601 표준을위한 파서를 작성하여 GitHub에 올려 놓았습니다 : https://github.com/boxed/iso8601. 이 구현은 기간, 간격,주기 간격 및 Python의 datetime 모듈에서 지원되는 날짜 범위를 벗어난 날짜를 제외하고 사양의 모든 것을 지원합니다.

    필자는 ISO 8601 표준을위한 파서를 작성하여 GitHub에 올려 놓았습니다 : https://github.com/boxed/iso8601. 이 구현은 기간, 간격,주기 간격 및 Python의 datetime 모듈에서 지원되는 날짜 범위를 벗어난 날짜를 제외하고 사양의 모든 것을 지원합니다.

    테스트가 포함되어 있습니다! :피

  15. ==============================

    15.저는 iso8601 유틸리티의 저자입니다. GitHub 또는 PyPI에서 찾을 수 있습니다. 예제를 파싱하는 방법은 다음과 같습니다.

    저는 iso8601 유틸리티의 저자입니다. GitHub 또는 PyPI에서 찾을 수 있습니다. 예제를 파싱하는 방법은 다음과 같습니다.

    >>> from iso8601utils import parsers
    >>> parsers.datetime('2008-09-03T20:56:35.450686Z')
    datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
    
  16. ==============================

    16.Django의 parse_datetime () 함수는 UTC 오프셋을 가진 날짜를 지원합니다 :

    Django의 parse_datetime () 함수는 UTC 오프셋을 가진 날짜를 지원합니다 :

    parse_datetime('2016-08-09T15:12:03.65478Z') =
    datetime.datetime(2016, 8, 9, 15, 12, 3, 654780, tzinfo=<UTC>)
    

    따라서 전체 프로젝트 내의 필드에서 ISO 8601 날짜를 파싱하는 데 사용할 수 있습니다.

    from django.utils import formats
    from django.forms.fields import DateTimeField
    from django.utils.dateparse import parse_datetime
    
    class DateTimeFieldFixed(DateTimeField):
        def strptime(self, value, format):
            if format == 'iso-8601':
                return parse_datetime(value)
            return super().strptime(value, format)
    
    DateTimeField.strptime = DateTimeFieldFixed.strptime
    formats.ISO_INPUT_FORMATS['DATETIME_INPUT_FORMATS'].insert(0, 'iso-8601')
    
  17. ==============================

    17.타사 모듈을 설치하지 않고 ISO 8601과 유사한 날짜 문자열을 지원되는 모든 Python 버전의 UNIX 타임 스탬프 또는 datetime.datetime 객체로 변환하는 간단한 방법은 SQLite의 날짜 구문 분석기를 사용하는 것입니다.

    타사 모듈을 설치하지 않고 ISO 8601과 유사한 날짜 문자열을 지원되는 모든 Python 버전의 UNIX 타임 스탬프 또는 datetime.datetime 객체로 변환하는 간단한 방법은 SQLite의 날짜 구문 분석기를 사용하는 것입니다.

    #!/usr/bin/env python
    from __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.123456Z is 1472140886 after epoch
    datetime is 2016-08-25 12:01:26
    2016-08-25T16:01:29 is 1472140889 after epoch
    datetime is 2016-08-25 12:01:29
    
  18. ==============================

    18.2.X 표준 라이브러리에서 작동하는 것을 시도해보십시오 :

    2.X 표준 라이브러리에서 작동하는 것을 시도해보십시오 :

    calendar.timegm(time.strptime(date.split(".")[0]+"UTC", "%Y-%m-%dT%H:%M:%S%Z"))
    

    calendar.timegm은 time.mktime의 gm 버전이 누락되었습니다.

  19. ==============================

    19.잘못된 날짜 문자열을 파싱하는 경우 python-dateutil이 예외를 throw하므로 예외를 catch 할 수 있습니다.

    잘못된 날짜 문자열을 파싱하는 경우 python-dateutil이 예외를 throw하므로 예외를 catch 할 수 있습니다.

    from dateutil import parser
    ds = '2012-60-31'
    try:
      dt = parser.parse(ds)
    except ValueError, e:
      print '"%s" is an invalid date' % ds
    
  20. ==============================

    20.ISO 8601에는 선택적 콜론과 대시가 여러 가지로 제공되기 때문에 기본적으로 CCYY-MM-DDThh : mm : ss [Z | (+ | -) hh : mm]입니다. strptime을 사용하려면 먼저 해당 변형을 제거해야합니다. 목표는 utc datetime 객체를 생성하는 것입니다. 2016-06-29T19 : 36 : 29.3453Z와 같이 Z 접미사가있는 UTC에서 작동하는 기본 사례 만 원한다면 :

    ISO 8601에는 선택적 콜론과 대시가 여러 가지로 제공되기 때문에 기본적으로 CCYY-MM-DDThh : mm : ss [Z | (+ | -) hh : mm]입니다. strptime을 사용하려면 먼저 해당 변형을 제거해야합니다. 목표는 utc datetime 객체를 생성하는 것입니다. 2016-06-29T19 : 36 : 29.3453Z와 같이 Z 접미사가있는 UTC에서 작동하는 기본 사례 만 원한다면 :

    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'는 '% Y % m % dT % H % M % S. % f % z'형식의 잘못된 지시어입니다) 수동으로 시간을 Z (UTC)에서 오프셋합니다. 참고 % z는 파이썬 버전 <3에서 시스템에서 작동하지 않을 수 있습니다. 이는 시스템 / 파이썬 빌드 유형 (즉 자이 썬, Cython 등)에 따라 달라지는 c 라이브러리 지원에 따라 달라지기 때문입니다.

    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
    
  21. ==============================

    21.요즘 인기있는 Requests : HTTP for Humans ™ 패키지 작성자 인 Maya : Datetime for Humans ™이 있습니다.

    요즘 인기있는 Requests : HTTP for Humans ™ 패키지 작성자 인 Maya : Datetime for Humans ™이 있습니다.

    >>> import maya
    >>> str = '2008-09-03T20:56:35.450686Z'
    >>> maya.MayaDT.from_rfc3339(str).datetime()
    datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=<UTC>)
    
  22. ==============================

    22.이 작업은 파이썬 3.2 이후의 stdlib에서 가능합니다 (모든 타임 스탬프가 UTC라고 가정).

    이 작업은 파이썬 3.2 이후의 stdlib에서 가능합니다 (모든 타임 스탬프가 UTC라고 가정).

    from datetime import datetime, timezone, timedelta
    datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%fZ").replace(
        tzinfo=timezone(timedelta(0)))
    

    예를 들어,

    >>> datetime.utcnow().replace(tzinfo=timezone(timedelta(0)))
    ... datetime.datetime(2015, 3, 11, 6, 2, 47, 879129, tzinfo=datetime.timezone.utc)
    
  23. ==============================

    23.위대한 Mark Amery의 대답 덕분에 모든 가능한 ISO 형식의 datetime을 설명하는 함수를 고안했습니다.

    위대한 Mark Amery의 대답 덕분에 모든 가능한 ISO 형식의 datetime을 설명하는 함수를 고안했습니다.

    class FixedOffset(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')
        except ValueError:
            pass
        try:
            return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S')
        except ValueError:
            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))
    
  24. ==============================

    24.

    def parseISO8601DateTime(datetimeStr):
        import time
        from datetime import datetime, timedelta
    
        def log_date_string(when):
            gmt = time.gmtime(when)
            if time.daylight and gmt[8]:
                tz = time.altzone
            else:
                tz = time.timezone
            if tz > 0:
                neg = 1
            else:
                neg = 0
                tz = -tz
            h, rem = divmod(tz, 3600)
            m, rem = divmod(rem, 60)
            if neg:
                offset = '-%02d%02d' % (h, m)
            else:
                offset = '+%02d%02d' % (h, m)
    
            return time.strftime('%d/%b/%Y:%H:%M:%S ', gmt) + offset
    
        dt = datetime.strptime(datetimeStr, '%Y-%m-%dT%H:%M:%S.%fZ')
        timestamp = dt.timestamp()
        return dt + timedelta(hours=dt.hour-time.gmtime(timestamp).tm_hour)
    

    문자열이 Z로 끝나지 않으면 우리는 % z를 사용하여 구문 분석 할 수 있습니다.

  25. from https://stackoverflow.com/questions/127803/how-do-i-parse-an-iso-8601-formatted-date by cc-by-sa and MIT license