How to convert a timezone aware string to datetime in Python without dateutil?
Domanda
I have to convert a timezone-aware string like "2012-11-01T04:16:13-04:00"
to a Python datetime
object.
I saw the dateutil
module which has a parse function, but I don't really want to use it as it adds a dependency.
So how can I do it? I have tried something like the following, but with no luck.
datetime.datetime.strptime("2012-11-01T04:16:13-04:00", "%Y-%m-%dT%H:%M:%S%Z")
Soluzione
As of Python 3.7, datetime.datetime.fromisoformat()
can handle your format:
>>> import datetime
>>> datetime.datetime.fromisoformat('2012-11-01T04:16:13-04:00')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))
In older Python versions you can't, not without a whole lot of painstaking manual timezone defining.
Python does not include a timezone database, because it would be outdated too quickly. Instead, Python relies on external libraries, which can have a far faster release cycle, to provide properly configured timezones for you.
As a side-effect, this means that timezone parsing also needs to be an external library. If dateutil
is too heavy-weight for you, use iso8601
instead, it'll parse your specific format just fine:
>>> import iso8601
>>> iso8601.parse_date('2012-11-01T04:16:13-04:00')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=<FixedOffset '-04:00'>)
iso8601
is a whopping 4KB small. Compare that tot python-dateutil
's 148KB.
As of Python 3.2 Python can handle simple offset-based timezones, and %z
will parse -hhmm
and +hhmm
timezone offsets in a timestamp. That means that for a ISO 8601 timestamp you'd have to remove the :
in the timezone:
>>> from datetime import datetime
>>> iso_ts = '2012-11-01T04:16:13-04:00'
>>> datetime.strptime(''.join(iso_ts.rsplit(':', 1)), '%Y-%m-%dT%H:%M:%S%z')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))
The lack of proper ISO 8601 parsing is being tracked in Python issue 15873.
Altri suggerimenti
Here is the Python Doc for datetime object using dateutil package..
from dateutil.parser import parse
get_date_obj = parse("2012-11-01T04:16:13-04:00")
print get_date_obj
There are two issues with the code in the original question: there should not be a :
in the timezone and the format string for "timezone as an offset" is lower case %z
not upper %Z
.
This works for me in Python v3.6
>>> from datetime import datetime
>>> t = datetime.strptime("2012-11-01T04:16:13-0400", "%Y-%m-%dT%H:%M:%S%z")
>>> print(t)
2012-11-01 04:16:13-04:00
You can convert like this.
date = datetime.datetime.strptime('2019-3-16T5-49-52-595Z','%Y-%m-%dT%H-%M-%S-%f%z')
date_time = date.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
I'm new to Python, but found a way to convert
2017-05-27T07:20:18.000-04:00
to
2017-05-27T07:20:18
without downloading new utilities.
from datetime import datetime, timedelta
time_zone1 = int("2017-05-27T07:20:18.000-04:00"[-6:][:3])
>>returns -04
item_date = datetime.strptime("2017-05-27T07:20:18.000-04:00".replace(".000", "")[:-6], "%Y-%m-%dT%H:%M:%S") + timedelta(hours=-time_zone1)
I'm sure there are better ways to do this without slicing up the string so much, but this got the job done.
This suggestion for using dateutil by Mohideen bin Mohammed definitely is the best solution even if it does a require a small library. having used the other approaches there prone to various forms of failure. Here's a nice function for this.
from dateutil.parser import parse
def parse_date_convert(date, fmt=None):
if fmt is None:
fmt = '%Y-%m-%d %H:%M:%S' # Defaults to : 2022-08-31 07:47:30
get_date_obj = parse(str(date))
return str(get_date_obj.strftime(fmt))
dates = ['2022-08-31T07:47:30Z','2022-08-31T07:47:29.098Z','2017-05-27T07:20:18.000-04:00','2012-11-01T04:16:13-04:00']
for date in dates:
print(f'Before: {date} After: {parse_date_convert(date)}')
Results:
Before: 2022-08-31T07:47:30Z After: 2022-08-31 07:47:30
Before: 2022-08-31T07:47:29.098Z After: 2022-08-31 07:47:29
Before: 2017-05-27T07:20:18.000-04:00 After: 2017-05-27 07:20:18
Before: 2012-11-01T04:16:13-04:00 After: 2012-11-01 04:16:13
Having tried various forms such as slicing split replacing the T Z like this:
dates = ['2022-08-31T07:47:30Z','2022-08-31T07:47:29.098Z','2017-05-27T07:20:18.000-04:00','2012-11-01T04:16:13-04:00']
for date in dates:
print(f'Before: {date} After: {date.replace("T", " ").replace("Z", "")}')
You still are left with subpar results. like the below
Before: 2022-08-31T07:47:30Z After: 2022-08-31 07:47:30
Before: 2022-08-31T07:47:29.098Z After: 2022-08-31 07:47:29.098
Before: 2017-05-27T07:20:18.000-04:00 After: 2017-05-27 07:20:18.000-04:00
Before: 2012-11-01T04:16:13-04:00 After: 2012-11-01 04:16:13-04:00
You can create a timezone unaware object and replace the tzinfo
and make it a timezone aware DateTime
object later.
from datetime import datetime
import pytz
unware_time = datetime.strptime("2012-11-01 04:16:13", "%Y-%m-%d %H:%M:%S")
aware_time = unaware_time.replace(tzinfo=pytz.UTC)