6

Due to my application's circumstances, I would prefer to use datetime.strptime instead of dateutil.parser.

After looking at the docs, I thought that %Y-%m-%dT%H:%M:%S%z may be the proper format for parsing a date string like this. Yet it still gives me an error.

Example

from datetime import datetime

d = '0000-00-00T00:00:00+00:00'
datetime.strptime(d, '%Y-%m-%dT%H:%M:%S%z')
ValueError: time data '0000-00-00T00:00:00+00:00' does not 
            match format '%Y-%m-%dT%H:%M:%S%z'
Jesse
  • 69
  • 1
  • 7
  • `0000-00-00T00:00:00+00:00` is an invalid value. There's no date 0. Have you tried to use a valid date string? – Panagiotis Kanavos May 29 '19 at 12:42
  • Possible duplicate of [How do I parse an ISO 8601-formatted date?](https://stackoverflow.com/questions/127803/how-do-i-parse-an-iso-8601-formatted-date) – Panagiotis Kanavos May 29 '19 at 12:48
  • Even with a valid string `%z` doesn't match the `HH:mm` format for offsets. The answers to the duplicate question show the alternatives, including `datetime.fromisoformat` in Python 3.7+ – Panagiotis Kanavos May 29 '19 at 12:52

3 Answers3

4

The easiest way to deal with timezones is to use dateutil.parser:

from dateutil.parser import parse
date_obj = parse('1970-01-01T00:00:00+00:00')

date_obj

> datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzutc())

But you have to pass a valid datetime-value (not only zeros...)

If you want to use strptime(), the timezone has to be in the format 0000 not 00:00, so this works:

d = '1900-02-05T11:43:32+0000'
datetime.strptime(d, '%Y-%m-%dT%H:%M:%S%z')

> datetime.datetime(1900, 2, 5, 11, 43, 32, tzinfo=datetime.timezone.utc)
ilja
  • 2,592
  • 2
  • 16
  • 23
  • Thank you. Your second block implementation using `strptime` is just what I was looking for. I will modify the date string's offset to omit the colon at the end of the string and then pass the modified version to `strptime`. – Jesse May 29 '19 at 21:37
1

Very late reply but for posterity, if you really want to parse it with strptime you can use %z

https://intellipaat.com/community/58366/the-strptime-example-for-datetime-with-tz-offset

Example:

datetime_string = "2021-01-01T10:25:00+00:00"
obj = datetime.strptime(datetime_string, "%Y-%m-%dT%H:%M:%S%z")
print(repr(obj))
>>> datetime.datetime(2021, 1, 1, 10, 25, tzinfo=datetime.timezone.utc)

datetime_string = datetime.strftime(obj, "%Y-%m-%dT%H:%M:%S%z")
print(datetime_string)
>>> 2021-01-01T10:25:00+0000

although notice the offset is now shown as +0000 which may be enough for you.

if you still insist on the output being the ISO 8601 format, and insist on using strftime to bring the format back to +00:00, you have to use a custom tzinfo object.

Example:

class TZ1(tzinfo):
    def utcoffset(self, dt): return timedelta(hours=0)
    def dst(self, dt):  return timedelta(0)
    def tzname(self, dt): return "+00:00"

datetime_string = "2021-01-01T10:25:00+00:00"
obj = datetime.strptime(datetime_string, "%Y-%m-%dT%H:%M:%S%z").replace(tzinfo=TZ1())
>>> datetime.datetime(2021, 1, 1, 10, 25, tzinfo=<__main__.TZ1 object at 0x7ff6e1c41f50>)

datetime_string = datetime.strftime(obj, "%Y-%m-%dT%H:%M:%S%Z")
print(datetime_string)
>>> 2021-01-01T10:25:00+00:00

This example is obviously hardcoded for UTC+0, but you can apply some logic based on the dt argument if necessary.

This approach can be quite useful (as opposed to the magic in the dateutil library) if you are setting up strict rules for dates and times in data processing from untrustworthy sources, to be used with validation, coercion etc. as you can set rigid inputs and outputs.

Edward
  • 1,806
  • 5
  • 26
  • 36
  • update: dateutil provides a `tzoffset` function to build this for you so you don't have to declare a class. example: `dt.replace(tzinfo=dateutil.tz.tzoffset(name="+00:00", offset=0))` source: https://dateutil.readthedocs.io/en/stable/tz.html#dateutil.tz.tzoffset – Edward Sep 14 '22 at 10:28
0

I'm not sure what you are trying to do with your code but the error is not given because of the wrong format but because '0000-00-00T00:00:00+00:00' is not a valid time, because zero is no date. If you try it with another time like: '1900-01-01T00:00:00+00:00' it should work just fine.

funie200
  • 3,688
  • 5
  • 21
  • 34
  • What do you mean with the standard offset format? The code seems to be running fine for me with my changes. – funie200 May 29 '19 at 13:08