Convert string that was originally a `timedelta` back into a `timedelta` object in Python
Question:
I have strings which were originally produced from timedelta
objects like so: print(f'{my_delta}')
.
I have many of these statements logged (e.g. "12:21:00", "1 day, 0:53:00", "2 days, 9:28:00") and I simply want to parse these logged statements to convert back to timedelta
objects. Is this possible with the datetime
library?
The strings were literally produced from just printing timedelta objects, but I cannot seem to convert back by using timedelta(my_string)
. Wondering if there is a standard way of doing this that I am missing.
Answers:
To convert the logged statements back to timedelta objects, you can use the datetime library’s datetime.strptime() function to parse the strings and extract the relevant information. Here’s an example of how you can do it:
from datetime import timedelta, datetime
def parse_timedelta_string(delta_string):
# Remove leading/trailing whitespace and split the string by commas and colons
parts = [part.strip() for part in delta_string.split(',') + delta_string.split(':')]
# Extract the days, hours, minutes, and seconds from the parts
days = 0
hours, minutes, seconds = 0, 0, 0
for part in parts:
if 'day' in part:
days = int(part.split()[0])
elif 'hour' in part:
hours = int(part.split()[0])
elif 'minute' in part:
minutes = int(part.split()[0])
elif 'second' in part:
seconds = int(part.split()[0])
# Create a timedelta object with the extracted values
delta = timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
return delta
# Example usage
delta_string = "2 days, 9:28:00"
delta = parse_timedelta_string(delta_string)
print(delta) # Output: 2 days, 9:28:00
In the example above, the parse_timedelta_string() function takes a delta string as input. It splits the string by commas and colons, then iterates over the parts to extract the days, hours, minutes, and seconds. Finally, it creates a timedelta object with the extracted values and returns it.
You can call this function for each logged statement you have to convert them back to timedelta objects.
This should be amenable to regex, since it seems very regular. It may have days specified at the beginning, or microseconds at the end. But its very… regular:
import re
pattern = r'''
((?P<days>-?d{1,}) days?, )? # maybe there will be day(s)
(?P<hours>d{1,2}) # hours will be one or 2 digits
:(?P<minutes>d{2}) # separated by a colon, minutes will be 2 digits
:(?P<seconds>d{2}) # separated by a colon, seconds will be 2 digits
(.(?P<microseconds>d{6}))? # maybe, separated by a period, microseconds will be 6 digits
'''
parse_timedelta_regex = re.compile(pattern, flags=re.VERBOSE)
Note, take care using the re.VERBOSE
flag with spaces, they are ignored outside of specific cases unless you escape them. But I do think it is more readable this way.
Examples of how to use this:
>> parse_timedelta_regex.search("1000 days, 0:00:00").groupdict()
{'days': '1000', 'hours': '0', 'minutes': '00', 'seconds': '00', 'microseconds': None}
>>> parse_timedelta_regex.search("1 day, 11:00:13.000130").groupdict()
{'days': '1', 'hours': '11', 'minutes': '00', 'seconds': '13', 'microseconds': '000130'}
You could also just write the function to convert the string to timedelta object like so:
>>> def string_to_timedelta(s):
... groups = parse_timedelta_regex.search(s).groupdict()
... args = {k:int(v) for k,v in groups.items() if v}
... return datetime.timedelta(**args)
...
>>> string_to_timedelta(str(datetime.timedelta(seconds=1337)))
datetime.timedelta(seconds=1337)
Here’s a more rigorous test (still not very rigorous):
>> def test_parse(n):
... for _ in range(n):
... seconds = random.random()*100_000_000
... td = datetime.timedelta(seconds=seconds)
... parsed = string_to_timedelta(str(td))
... assert td == parsed
...
>>> test_parse(1000)
>>> test_parse(10_000)
>>> test_parse(100_000)
As others have noted emphatically, the datetime
library does not seem to support this functionality.
Here’s a one-liner that uses regex:
>>> from datetime import timedelta
>>> import re
>>>
>>> str_to_dlt = lambda t: timedelta(days=int((m:=re.match(r'((d+)sdays?,s*)?(d{1,2}):(d{2}):(d{2})', t))[2] or 0), hours=int(m[3]), minutes=int(m[4]), seconds=int(m[5]))
Printing the timedelta returns the original string it was supplied:
>>> print(str_to_dlt('5:11:13'))
5:11:13
>>>
>>> print(str_to_dlt('1 day, 5:11:13'))
1 day, 5:11:13
>>>
>>> print(str_to_dlt('2 days, 5:11:13'))
2 days, 5:11:13
I have strings which were originally produced from timedelta
objects like so: print(f'{my_delta}')
.
I have many of these statements logged (e.g. "12:21:00", "1 day, 0:53:00", "2 days, 9:28:00") and I simply want to parse these logged statements to convert back to timedelta
objects. Is this possible with the datetime
library?
The strings were literally produced from just printing timedelta objects, but I cannot seem to convert back by using timedelta(my_string)
. Wondering if there is a standard way of doing this that I am missing.
To convert the logged statements back to timedelta objects, you can use the datetime library’s datetime.strptime() function to parse the strings and extract the relevant information. Here’s an example of how you can do it:
from datetime import timedelta, datetime
def parse_timedelta_string(delta_string):
# Remove leading/trailing whitespace and split the string by commas and colons
parts = [part.strip() for part in delta_string.split(',') + delta_string.split(':')]
# Extract the days, hours, minutes, and seconds from the parts
days = 0
hours, minutes, seconds = 0, 0, 0
for part in parts:
if 'day' in part:
days = int(part.split()[0])
elif 'hour' in part:
hours = int(part.split()[0])
elif 'minute' in part:
minutes = int(part.split()[0])
elif 'second' in part:
seconds = int(part.split()[0])
# Create a timedelta object with the extracted values
delta = timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
return delta
# Example usage
delta_string = "2 days, 9:28:00"
delta = parse_timedelta_string(delta_string)
print(delta) # Output: 2 days, 9:28:00
In the example above, the parse_timedelta_string() function takes a delta string as input. It splits the string by commas and colons, then iterates over the parts to extract the days, hours, minutes, and seconds. Finally, it creates a timedelta object with the extracted values and returns it.
You can call this function for each logged statement you have to convert them back to timedelta objects.
This should be amenable to regex, since it seems very regular. It may have days specified at the beginning, or microseconds at the end. But its very… regular:
import re
pattern = r'''
((?P<days>-?d{1,}) days?, )? # maybe there will be day(s)
(?P<hours>d{1,2}) # hours will be one or 2 digits
:(?P<minutes>d{2}) # separated by a colon, minutes will be 2 digits
:(?P<seconds>d{2}) # separated by a colon, seconds will be 2 digits
(.(?P<microseconds>d{6}))? # maybe, separated by a period, microseconds will be 6 digits
'''
parse_timedelta_regex = re.compile(pattern, flags=re.VERBOSE)
Note, take care using the re.VERBOSE
flag with spaces, they are ignored outside of specific cases unless you escape them. But I do think it is more readable this way.
Examples of how to use this:
>> parse_timedelta_regex.search("1000 days, 0:00:00").groupdict()
{'days': '1000', 'hours': '0', 'minutes': '00', 'seconds': '00', 'microseconds': None}
>>> parse_timedelta_regex.search("1 day, 11:00:13.000130").groupdict()
{'days': '1', 'hours': '11', 'minutes': '00', 'seconds': '13', 'microseconds': '000130'}
You could also just write the function to convert the string to timedelta object like so:
>>> def string_to_timedelta(s):
... groups = parse_timedelta_regex.search(s).groupdict()
... args = {k:int(v) for k,v in groups.items() if v}
... return datetime.timedelta(**args)
...
>>> string_to_timedelta(str(datetime.timedelta(seconds=1337)))
datetime.timedelta(seconds=1337)
Here’s a more rigorous test (still not very rigorous):
>> def test_parse(n):
... for _ in range(n):
... seconds = random.random()*100_000_000
... td = datetime.timedelta(seconds=seconds)
... parsed = string_to_timedelta(str(td))
... assert td == parsed
...
>>> test_parse(1000)
>>> test_parse(10_000)
>>> test_parse(100_000)
As others have noted emphatically, the datetime
library does not seem to support this functionality.
Here’s a one-liner that uses regex:
>>> from datetime import timedelta
>>> import re
>>>
>>> str_to_dlt = lambda t: timedelta(days=int((m:=re.match(r'((d+)sdays?,s*)?(d{1,2}):(d{2}):(d{2})', t))[2] or 0), hours=int(m[3]), minutes=int(m[4]), seconds=int(m[5]))
Printing the timedelta returns the original string it was supplied:
>>> print(str_to_dlt('5:11:13'))
5:11:13
>>>
>>> print(str_to_dlt('1 day, 5:11:13'))
1 day, 5:11:13
>>>
>>> print(str_to_dlt('2 days, 5:11:13'))
2 days, 5:11:13