How do I parse an ISO 8601-formatted date?

后端 未结 27 2319
小鲜肉
小鲜肉 2020-11-21 06:08

I need to parse RFC 3339 strings like \"2008-09-03T20:56:35.450686Z\" into Python\'s datetime type.

I have found strptime in the Python sta

27条回答
  •  迷失自我
    2020-11-21 06:36

    Initially I tried with:

    from operator import neg, pos
    from time import strptime, mktime
    from datetime import datetime, tzinfo, timedelta
    
    class MyUTCOffsetTimezone(tzinfo):
        @staticmethod
        def with_offset(offset_no_signal, signal):  # type: (str, str) -> MyUTCOffsetTimezone
            return MyUTCOffsetTimezone((pos if signal == '+' else neg)(
                (datetime.strptime(offset_no_signal, '%H:%M') - datetime(1900, 1, 1))
              .total_seconds()))
    
        def __init__(self, offset, name=None):
            self.offset = timedelta(seconds=offset)
            self.name = name or self.__class__.__name__
    
        def utcoffset(self, dt):
            return self.offset
    
        def tzname(self, dt):
            return self.name
    
        def dst(self, dt):
            return timedelta(0)
    
    
    def to_datetime_tz(dt):  # type: (str) -> datetime
        fmt = '%Y-%m-%dT%H:%M:%S.%f'
        if dt[-6] in frozenset(('+', '-')):
            dt, sign, offset = strptime(dt[:-6], fmt), dt[-6], dt[-5:]
            return datetime.fromtimestamp(mktime(dt),
                                          tz=MyUTCOffsetTimezone.with_offset(offset, sign))
        elif dt[-1] == 'Z':
            return datetime.strptime(dt, fmt + 'Z')
        return datetime.strptime(dt, fmt)
    

    But that didn't work on negative timezones. This however I got working fine, in Python 3.7.3:

    from datetime import datetime
    
    
    def to_datetime_tz(dt):  # type: (str) -> datetime
        fmt = '%Y-%m-%dT%H:%M:%S.%f'
        if dt[-6] in frozenset(('+', '-')):
            return datetime.strptime(dt, fmt + '%z')
        elif dt[-1] == 'Z':
            return datetime.strptime(dt, fmt + 'Z')
        return datetime.strptime(dt, fmt)
    

    Some tests, note that the out only differs by precision of microseconds. Got to 6 digits of precision on my machine, but YMMV:

    for dt_in, dt_out in (
            ('2019-03-11T08:00:00.000Z', '2019-03-11T08:00:00'),
            ('2019-03-11T08:00:00.000+11:00', '2019-03-11T08:00:00+11:00'),
            ('2019-03-11T08:00:00.000-11:00', '2019-03-11T08:00:00-11:00')
        ):
        isoformat = to_datetime_tz(dt_in).isoformat()
        assert isoformat == dt_out, '{} != {}'.format(isoformat, dt_out)
    

提交回复
热议问题