How to construct a timedelta object from a simple string

我只是一个虾纸丫 提交于 2019-11-26 15:10:54
virhilo

for the 4:13, and other standard formats(but if you don't know which one) use dateutil.parser.parse from python-dateutil

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.iteritems():
        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)
>>> 

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())
wildwilhelm

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

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)

If you use Python 3 then here's updated version for Hari Shankar's solution, which I used:

from datetime import timedelta
import re

regex = re.compile(r'(?P<hours>\d+?)/'
                   r'(?P<minutes>\d+?)/'
                   r'(?P<seconds>\d+?)$')

def parse_time(time_str):
    parts = regex.match(time_str)
    if not parts:
        return
    parts = parts.groupdict()
    print(parts)
    time_params = {}
    for name, param in parts.items():
        if param:
            time_params[name] = int(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).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!