Wednesday, August 15, 2007

Python: Reconstructing timedeltas from strings

For some reason, the date/time objects implemented by the datetime module have no methods to construct them from their own string representations (as returned by calling str() or unicode() on the objects). It so happens that reconstructing a timedelta from its string representation can be implemented using a relatively simple regular expression:
import re
from datetime import timedelta

def parseTimeDelta(s):
"""Create timedelta object representing time delta
expressed in a string

Takes a string in the format produced by calling str() on
a python timedelta object and returns a timedelta instance
that would produce that string.

Acceptable formats are: "X days, HH:MM:SS" or "HH:MM:SS".
"""
if s is None:
return None
d = re.match(
r'((?P<days>\d+) days, )?(?P<hours>\d+):'
r'(?P<minutes>\d+):(?P<seconds>\d+)',
str(s)).groupdict(0)
return timedelta(**dict(( (key, int(value))
for key, value in d.items() )))

But the other types are not quite so easy. Next time, I'll post my implementation for reconstructing datetime objects from their string representation.

8 comments:

Anonymous said...

Have a look at dateutil also: http://labix.org/python-dateutil

Kelly Yancey said...

Lawrence: Thanks for the comment. I was aware of that package but it is considerable overkill. I only want the datetime module to be able to consume its own output. I don't really think that is too much to ask from a module in the standard library.

I'm secretly hoping that by showing how it can be done using other standard modules, someone with sway in the python development community might pick it up and add it to the datetime module. :)

Now, if someone were to get the entire dateutil module into the standard library and the datetime object initializers were extended to accept strings that were parsed via the dateutil module, that would really rock.

Anonymous said...

J'aurais mis un point d'interrogation à aprés le "days" sinon on a l'erreur "'NoneType' object has no attribute 'groupdict'" quand le nombre de jour est égale à 1.
PS :J'ai remplacé "<" ">" par des crochets "[" "]"

Avant :
...
r'((?P[days]\d+) days, )?
...

Aprés :
...
r'((?P[days]\d+) days?, )?
...

Rodrigue

Demolishun said...
This comment has been removed by the author.
Demolishun said...

This will convert from str(timedelta) to timedelta

data = time.split(":")
time = timedelta(hours=int(data[0]),
minutes=int(data[1]),
seconds=float(data[2]))

Edgar Costa said...

Just a remark, the timedelta also can give you something like:
"1 day, HH:MM:SS"

tk u for the script

Alexander Pitchford said...

Hey, thanks for this script.

I spent a lot of time looking for this. Lots of answers out there for parsing weird date formats, but I just wanted to get a timedelta back from what I wrote into a file!

As far as I can tell there is still no (nice simple) solution to this in the standard library.

Thanks again

Alex

Alexander Pitchford said...

I had to make some small adjustment to your script (see below).
Specifically it had problems with "1 day, HH:MM:SS" and it ignored my microseconds.
So I changed the regex, the type cast, and the comments accordingly.


"""Create timedelta object representing time delta
expressed in a string

Takes a string in the format produced by calling str() on
a python timedelta object and returns a timedelta instance
that would produce that string.

Acceptable formats are:
"HH:MM:SS"
"X day, HH:MM:SS"
"X days, HH:MM:SS"
"HH:MM:SS.us"
"X day, HH:MM:SS.us"
"X days, HH:MM:SS.us"
where "us" refer to micro seconds
"""
if s is None:
return None
d = re.match(
r'((?P\d+) days?, )?(?P\d+):'
r'(?P\d+):(?P\d+(\.\d+)?)',
str(s)).groupdict(0)
return timedelta(**dict(( (key, float(value))
for key, value in d.items() )))