I recommend using python-dateutil. Its parser has been able to parse every date format I've thrown at it so far.
>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)
and so on. No dealing with strptime() format nonsense... just throw a date at it and it Does The Right Thing.
I recommend using python-dateutil. Its parser has been able to parse every date format I've thrown at it so far.
>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)
and so on. No dealing with strptime() format nonsense... just throw a date at it and it Does The Right Thing.
Since strptime returns a datetime object which has tzinfo attribute, We can simply replace it with desired timezone.
>>> import datetime
>>> date_time_str = '2018-06-29 08:15:27.243860'
>>> date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S.%f').replace(tzinfo=datetime.timezone.utc)
>>> date_time_obj.tzname()
'UTC'
`Time::Piece` and `strptime()` processing timezones documentation discrepancy
Using strftime from Datetime with "+02:00" as UTC/timezone?
datetime - How to parse dates with -0400 timezone string in Python? - Stack Overflow
python - Convert timestamps with offset to datetime obj using strptime - Stack Overflow
How to use strptime() parsing a datetime string with a timezone offset?
Is it possible to use the strptime() to handle the UTC or named time zones (e.g., EST, PST)?
What happens if the datetime string does not have a timezone offset?
You can use dateutil's parse for that:
from dateutil.parser import parse
s = '2019-04-10 21:49:41.607472+00'
parse(s)
datetime.datetime(2019, 4, 10, 21, 49, 41, 607472, tzinfo=tzutc())
strptime uses %z to specify a UTC offset in the format of ±HHMM[SS[.ffffff]]. Since minutes are required and your sample input only has hours, you can concatenate '00' to the string before parsing:
datetime.strptime(s + '00', '%Y-%m-%d %H:%M:%S.%f%z')
My log files have the date/time formatted as: 2022-01-01T11:53:42-08:00. I need to convert that to a Unixtime. I think strptime() is the easiest way to do this?
Here is the code I came up with to process this specific time string.
#!/usr/bin/env perl use strict; use warnings; use Time::Piece; my $input = '2022-01-01T11:53:42-08:00'; my $tp = Time::Piece->strptime($input, "%Y-%m-%dT%H:%M:%S"); print "Input : $input\n"; print "Epoch : " . $tp->epoch . "\n"; print "Format: " . $tp->cdate . "\n";
When I run this I get an error about the timezone string at the end
Garbage at end of string in strptime: -08:00 at /usr/lib64/perl5/Time/Piece.pm line 598. Perhaps a format flag did not match the actual input? at /usr/lib64/perl5/Time/Piece.pm line 598.
The documentation says to add %z to process timezones, but when I do that it fails completely. How do I make strptime() process this string correctly? Is there a better/easier way to convert this?
I have the following string:
"2020-06-13T17:27:24.165+02:00"
I'm trying to format it like this:
'%Y-%m-%dT%H:M:%S.%f%z'
But I get this error:
ValueError: time data '2020-06-27T10:18:01.411+02:00' does not match format '%Y-%m-%dT%H:M:%S.%f%z' (match)
Maybe it's because:
%z: UTC offset in the form +HHMM or -HHMM (empty string if the the object is naive).
Maybe it's because I have +02:00, but I should have +0200? Or did I make another mistake?
What do you guys think? What's the best way to solve this?
You can use the parse function from dateutil:
>>> from dateutil.parser import parse
>>> d = parse('2009/05/13 19:19:30 -0400')
>>> d
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400))
This way you obtain a datetime object you can then use.
As answered, dateutil2.0 is written for Python 3.0 and does not work with Python 2.x. For Python 2.x dateutil1.5 needs to be used.
%z is supported in Python 3.2+:
>>> from datetime import datetime
>>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z')
datetime.datetime(2009, 5, 13, 19, 19, 30,
tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))
On earlier versions:
from datetime import datetime
date_str = '2009/05/13 19:19:30 -0400'
naive_date_str, _, offset_str = date_str.rpartition(' ')
naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(repr(dt))
# -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240))
print(dt)
# -> 2009-05-13 19:19:30-04:00
where FixedOffset is a class based on the code example from the docs:
from datetime import timedelta, tzinfo
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)
The Python 2 strptime() function indeed does not support the %z format for timezones (because the underlying time.strptime() function doesn't support it). You have two options:
Ignore the timezone when parsing with
strptime:time_obj = datetime.datetime.strptime(time_str[:19], '%Y-%m-%dT%H:%M:%S')use the
dateutilmodule, it's parse function does deal with timezones:from dateutil.parser import parse time_obj = parse(time_str)
Quick demo on the command prompt:
>>> from dateutil.parser import parse
>>> parse("2012-07-24T23:14:29-07:00")
datetime.datetime(2012, 7, 24, 23, 14, 29, tzinfo=tzoffset(None, -25200))
You could also upgrade to Python 3.2 or newer, where timezone support has been improved to the point that %z would work, provided you remove the last : from the input, and the - from before the %z:
>>> import datetime
>>> time_str = "2012-07-24T23:14:29-07:00"
>>> datetime.datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S%z')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2012-07-24T23:14:29-07:00' does not match format '%Y-%m-%dT%H:%M:%S%z'
>>> ''.join(time_str.rsplit(':', 1))
'2012-07-24T23:14:29-0700'
>>> datetime.datetime.strptime(''.join(time_str.rsplit(':', 1)), '%Y-%m-%dT%H:%M:%S%z')
datetime.datetime(2012, 7, 24, 23, 14, 29, tzinfo=datetime.timezone(datetime.timedelta(-1, 61200)))
In Python 3.7+:
from datetime import datetime
time_str = "2012-07-24T23:14:29-07:00"
dt_aware = datetime.fromisoformat(time_str)
print(dt_aware.isoformat('T'))
# -> 2012-07-24T23:14:29-07:00
In Python 3.2+:
from datetime import datetime
time_str = "2012-07-24T23:14:29-0700"
dt_aware = datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S%z')
print(dt_aware.isoformat('T'))
# -> 2012-07-24T23:14:29-07:00
Note: Before Python 3.7 this variant didn't support : in the -0700 part (both formats are allowed by rfc 3339). See datetime: add ability to parse RFC 3339 dates and times.
On older Python versions such as Python 2.7, you could parse the utc offset manually:
from datetime import datetime
time_str = "2012-07-24T23:14:29-0700"
# split the utc offset part
naive_time_str, offset_str = time_str[:-5], time_str[-5:]
# parse the naive date/time part
naive_dt = datetime.strptime(naive_time_str, '%Y-%m-%dT%H:%M:%S')
# parse the utc offset
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(dt.isoformat('T'))
where FixedOffset class is defined here.
You're looking for %z:
>>> datetime.strptime('2020-10-23T11:50:19+00:00', '%Y-%m-%dT%H:%M:%S%z')
datetime.datetime(2020, 10, 23, 11, 50, 19, tzinfo=datetime.timezone.utc)
Beware of some Python version compatibility notes:
Changed in version 3.7: When the
%zdirective is provided to thestrptime()method, the UTC offsets can have a colon as a separator between hours, minutes and seconds. For example,'+01:00:00'will be parsed as an offset of one hour. In addition, providing'Z'is identical to'+00:00'.
More robust approach, it's not strptime, but it's still in stdlib since Python 3.7:
>>> datetime.fromisoformat('2020-10-23T11:50:19+00:00')
datetime.datetime(2020, 10, 23, 11, 50, 19, tzinfo=datetime.timezone.utc)
As documented this function supports strings in the format:
YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]
where * can match any single character (not just a T).
The dateutil.parser function will parse that timezone format:
from dateutil.parser import parse
dt = parse('2020-10-23T11:50:19+00:00')
print(dt.date())
print(dt.time())
print(dt.tzinfo)
Result:
2020-10-23
11:50:19
tzutc()
You can combine the separate date, time and tzinfo objects into a datetime, if that's what you need, like this:
dt = datetime.combine(dt.date(), dt.time(), tzinfo=dt.tzinfo)
print(dt)
Result:
2020-10-23 11:50:19+00:00