Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct a timedelta object from a simple string

People also ask

How do you convert a string to a Timedelta?

Convert String to TimeDelta We can even convert time in string format to datetime by using the strptime() function and then extracting the timedelta information using the timedelta module. We can use the repr(td) to print the timedelta as a constructor with attributes in a string format.

What is a Timedelta object?

timedelta Objects. A timedelta object represents a duration, the difference between two dates or times. class datetime. timedelta (days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

How do you write Timedelta in Python?

Python timedelta() function is present under datetime library which is generally used for calculating differences in dates and also can be used for date manipulations in Python. It is one of the easiest ways to perform date manipulations. Code #1: Python3.


To me the most elegant solution, without having to resort to external libraries such as dateutil or manually parsing the input, is to use datetime's powerful strptime string parsing method.

from datetime import datetime, timedelta
# we specify the input and the format...
t = datetime.strptime("05:20:25","%H:%M:%S")
# ...and use datetime's hour, min and sec properties to build a timedelta
delta = timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)

After this you can use your timedelta object as normally, convert it to seconds to make sure we did the correct thing etc.

print(delta)
assert(5*60*60+20*60+25 == delta.total_seconds())

I had a bit of time on my hands yesterday, so I developed @virhilo's answer into a Python module, adding a few more time expression formats, including all those requested by @priestc.

Source code is on github (MIT License) for anybody that wants it. It's also on PyPI:

pip install pytimeparse

Returns the time as a number of seconds:

>>> from pytimeparse.timeparse import timeparse
>>> timeparse('32m')
1920
>>> timeparse('2h32m')
9120
>>> timeparse('4:13')
253
>>> timeparse('5hr34m56s')
20096
>>> timeparse('1.2 minutes')
72

For the first format (5hr34m56s), you should parse using regular expressions

Here is re-based solution:

import re
from datetime import timedelta


regex = re.compile(r'((?P<hours>\d+?)hr)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')


def parse_time(time_str):
    parts = regex.match(time_str)
    if not parts:
        return
    parts = parts.groupdict()
    time_params = {}
    for name, param in parts.items():
        if param:
            time_params[name] = int(param)
    return timedelta(**time_params)


>>> from parse_time import parse_time
>>> parse_time('12hr')
datetime.timedelta(0, 43200)
>>> parse_time('12hr5m10s')
datetime.timedelta(0, 43510)
>>> parse_time('12hr10s')
datetime.timedelta(0, 43210)
>>> parse_time('10s')
datetime.timedelta(0, 10)
>>> 

I wanted to input just a time and then add it to various dates so this worked for me:

from datetime import datetime as dtt

time_only = dtt.strptime('15:30', "%H:%M") - dtt.strptime("00:00", "%H:%M")

I've modified virhilo's nice answer with a few upgrades:

  • added a assertion that the string is a valid time string
  • replace the "hr" hour-indicator with "h"
  • allow for a "d" - days indicator
  • allow non-integer times (e.g. 3m0.25s is 3 minutes, 0.25 seconds)

.

import re
from datetime import timedelta


regex = re.compile(r'^((?P<days>[\.\d]+?)d)?((?P<hours>[\.\d]+?)h)?((?P<minutes>[\.\d]+?)m)?((?P<seconds>[\.\d]+?)s)?$')


def parse_time(time_str):
    """
    Parse a time string e.g. (2h13m) into a timedelta object.

    Modified from virhilo's answer at https://stackoverflow.com/a/4628148/851699

    :param time_str: A string identifying a duration.  (eg. 2h13m)
    :return datetime.timedelta: A datetime.timedelta object
    """
    parts = regex.match(time_str)
    assert parts is not None, "Could not parse any time information from '{}'.  Examples of valid strings: '8h', '2d8h5m20s', '2m4s'".format(time_str)
    time_params = {name: float(param) for name, param in parts.groupdict().items() if param}
    return timedelta(**time_params)

Django comes with the utility function parse_duration(). From the documentation:

Parses a string and returns a datetime.timedelta.

Expects data in the format "DD HH:MM:SS.uuuuuu" or as specified by ISO 8601 (e.g. P4DT1H15M20S which is equivalent to 4 1:15:20) or PostgreSQL's day-time interval format (e.g. 3 days 04:05:06).


if you want to use : as separator, I use this function:

import re
from datetime import timedelta

def timedelta_parse(value):
    """
    convert input string to timedelta
    """
    value = re.sub(r"[^0-9:]", "", value)
    if not value:
        return

    return timedelta(**{key:float(val)
                        for val, key in zip(value.split(":")[::-1], 
                                            ("seconds", "minutes", "hours", "days"))
               })

Examples:

In [4]: timedelta_pars("1:0:0:1")
Out[4]: datetime.timedelta(days=1, seconds=1)

In [5]: timedelta_pars("123.5")
Out[5]: datetime.timedelta(seconds=123, microseconds=500000)

In [6]: timedelta_pars("1:6:34:9.983")
Out[6]: datetime.timedelta(days=1, seconds=23649, microseconds=983000)

In [8]: timedelta_pars("23:45:00")
Out[8]: datetime.timedelta(seconds=85500)