Search code examples
python-3.xdatetimeutcrfc3339

can't subtract offset-naive and offset-aware datetimes while subtracting date with offset mentioned


My basic requirement is I have a datetime string dt_a_str and I have to calculate the difference between it and current datetime. However, with my current code i get following error:

Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> dt_a_str = '2022-04-16T14:27:47.1069564Z'
>>> dt_a = datetime.datetime.strptime(dt_a_str, "%Y-%m-%dT%H:%M:%S.%f4Z")
>>> dt_b = datetime.datetime.now(datetime.timezone.utc)
>>> diff = abs((dt_b - dt_a).seconds)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't subtract offset-naive and offset-aware datetimes

As per my understanding I am converting time along with offset that is .%f4Z" but why it still saying that is it as a offset-naive date.


Solution

  • You can only compare datetime objects that are either both naive (no tzinfo) or both aware (tzinfo set). Using a literal Z in the parsing directive does not parse Z to UTC. It just makes the parser ignore it, like you could do with any character (such as ':' for instance).

    With Python 3.11, fromisoformat handles 7 digits of fractional seconds and parse the Z to UTC:

    Python 3.11.3 (main, May  3 2023, 11:09:17) [GCC 11.3.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    
    from datetime import datetime
    dt_a_str = '2022-04-16T14:27:47.1069564Z'
    
    print(datetime.fromisoformat(dt_a_str))
    2022-04-16 14:27:47.106956+00:00
    

    formisoformat was upgraded in 3.11, so for older Python versions, a third party parser is probably the safer option. E.g.

    from dateutil.parser import isoparse
    dt_a_str = '2022-04-16T14:27:47.1069564Z'
    
    print(isoparse(dt_a_str))
    2022-04-16 14:27:47.106956+00:00
    

    or

    from iso8601 import parse_date
    dt_a_str = '2022-04-16T14:27:47.1069564Z'
    
    print(parse_date(dt_a_str))
    2022-04-16 14:27:47.106956+00:00