如何从简单字符串构造 timedelta 对象

2025-01-22 08:45:00
admin
原创
133
摘要:问题描述:我正在编写一个需要将字符串解析为的函数timedelta。用户必须输入类似"32m"或"2h32m",甚至"4:13"或 的内容"5hr34m56s"... 是否有库或已实现此类功能的东西?解决方案 1:对我来说,最优雅...

问题描述:

我正在编写一个需要将字符串解析为的函数timedelta。用户必须输入类似"32m""2h32m",甚至"4:13"或 的内容"5hr34m56s"... 是否有库或已实现此类功能的东西?


解决方案 1:

对我来说,最优雅的解决方案是使用datetime强大的字符串解析方法,而无需借助dateutil等外部库或手动解析输入。strptime

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)

此后,您可以正常使用 timedelta 对象,将其转换为秒以确保我们做了正确的事情等等。

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

解决方案 2:

我昨天有点时间,所以我将@virhilo的答案开发成一个 Python 模块,添加了一些时间表达格式,包括@priestc要求的所有格式。

源代码位于 github(MIT 许可证),任何人需要都可以使用。它也位于 PyPI 上:

pip install pytimeparse

以秒数返回时间:

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

解决方案 3:

对于第一种格式(5hr34m56s),你应该使用正则表达式进行解析

以下是重新制定的解决方案:

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

解决方案 4:

如果 Pandas 已经在你的依赖项中,它可以很好地完成此操作:

>>> import pandas as pd
>>> pd.Timedelta('5hr34m56s')
Timedelta('0 days 05:34:56')

>>> pd.Timedelta('2h32m')
Timedelta('0 days 02:32:00')

>>> pd.Timedelta('5hr34m56s')
Timedelta('0 days 05:34:56')

>>> # It is pretty forgiving:
>>> pd.Timedelta('2 days 24:30:00 10 sec')
Timedelta('3 days 00:30:10')

如果您喜欢该类型,请转换为datetime.timedelta

>>> pd.Timedelta('1 days').to_pytimedelta()
datetime.timedelta(1)

不幸的是,这不起作用:

>>> pd.Timedelta('4:13')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pandas_libs    slibs    imedeltas.pyx", line 1217, in 
pandas._libs.tslibs.timedeltas.Timedelta.__new__
  File "pandas_libs    slibs    imedeltas.pyx", line 454, in 
pandas._libs.tslibs.timedeltas.parse_timedelta_string
ValueError: expected hh:mm:ss format

尽管这不是 Pandas 的主要目的,但实际上它具有相当广泛的日期和时间工具。

要安装 Pandas:

# If you use pip
pip install pandas

# If you use conda
conda install pandas

解决方案 5:

我想输入一个时间,然后将其添加到不同的日期,所以这对我有用:

from datetime import datetime as dtt

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

解决方案 6:

我修改了virhilo 的答案并做了一些升级:

  • 添加了断言,表明该字符串是有效的时间字符串

  • 将小时指示器“hr”替换为“h”

  • 允许“d”-天数指示

  • 允许非整数时间(例如3m0.25s3 分钟,0.25 秒)

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)

解决方案 7:

使用isodate库解析 ISO 8601 持续时间字符串。例如:

isodate.parse_duration('PT1H5M26S')

另请参阅是否有一种简单的方法将 ISO 8601 持续时间转换为时间增量?

解决方案 8:

Django 自带了实用函数parse_duration()。摘自文档:

解析字符串并返回datetime.timedelta

期望数据格式为"DD HH:MM:SS.uuuuuu"或符合 ISO 8601 的规定(例如P4DT1H15M20S相当于4 1:15:20)或 PostgreSQL 的天时间间隔格式(例如3 days 04:05:06)。

解决方案 9:

如果您想使用:作为分隔符,我使用此功能:

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"))
               })

例子:

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

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

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

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

解决方案 10:

如果你使用 Python 3,那么这里是我使用的 Hari Shankar 解决方案的更新版本:

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)

解决方案 11:

考虑尝试tempora.parse_timedelta(来自tempora)。

$ pip-run 'tempora>=4.1.1' -- -q
>>> from tempora import parse_timedelta
>>> parse_timedelta("32m")
datetime.timedelta(seconds=1920)
>>> parse_timedelta("2h32m")
datetime.timedelta(seconds=9120)
>>> parse_timedelta("4:13")
datetime.timedelta(seconds=15180)
>>> parse_timedelta("5hr34m56s")
datetime.timedelta(seconds=20096)

解决方案 12:

import re
from datetime import timedelta

class InvalidTimeString(Exception):
    """Exception raised when the input string is not a valid time string."""

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

def parse_time(time_str: str) -> timedelta | None:
    """
    Parse a time string into a timedelta object.

    Args:
        time_str (str): The time string to parse. This can include hours ("Xhr"), minutes ("Ym"), and seconds ("Zs").
            Each component is optional and can appear in any order, but they should be separated by non-numeric characters.

    Returns:
        timedelta: A timedelta object representing the time in the input string.

    Raises:
        InvalidTimeString: If the input string is not a valid time string.

    Usage:
    >>> parse_time('12hr5m10s')
    datetime.timedelta(seconds=43510)
    >>> parse_time('12hr')
    datetime.timedelta(seconds=43200)
    >>> parse_time('12hr10s')
    datetime.timedelta(seconds=43210)
    >>> parse_time('12hr5m10s')
    datetime.timedelta(seconds=43510)
    >>> parse_time('5m10s12hr')
    datetime.timedelta(seconds=43510)
    """
    time_params = {"hours": 0, "minutes": 0, "seconds": 0}
    matches = _TIME_REGEX.finditer(time_str)
    if not matches:
        raise InvalidTimeString(f"'{time_str}' is not a valid time string")

    for match in matches:
        match_dict = match.groupdict()
        for name, param in match_dict.items():
            if param:
                time_params[name] = int(param)

    return timedelta(**time_params)

parse_time函数用于将时间字符串解析为 Python timedelta 对象。输入的时间字符串可以按任意顺序包含小时(“Xhr”)、分钟(“Ym”)和秒(“Zs”)。每个组件都是可选的,可以用非数字字符分隔。

该函数首先定义一个能够匹配这些时间字符串组件的正则表达式。此正则表达式包括小时、分钟和秒的命名组,这使得以后提取这些值更加容易。

接下来,该函数使用正则表达式的 finditer 方法查找输入字符串中的所有匹配项。此方法返回一个迭代器,该迭代器为字符串中正则表达式模式的每个非重叠匹配项生成匹配对象。

然后,该函数迭代每个匹配项,使用 groupdict 方法将匹配对象转换为字典。此方法返回一个字典,其中包含在匹配项中找到的所有命名组,其中组名称为键,匹配的字符串为值。

对于字典中的每个命名组,该函数会检查该组是否有值。如果有,该函数会将该值转换为整数,并将其存储在 time_params 字典中的相应键(小时、分钟或秒)下。

最后,该函数timedelta从 time_params 字典中创建一个对象并返回它。

使用此方法有几个优点:

  1. 灵活性:该函数可以处理多种格式的时间字符串,使其在不同情况下更有用。

  2. 稳健性:该函数包含错误检查,以确保输入字符串是有效的时间字符串。如果不是,该函数会引发自定义异常来表明这一点。

  3. 可读性:使用正则表达式和命名组使得代码更具可读性,更易于理解。

  4. 效率:通过使用字典来存储时间分量并使用 timedelta 对象来表示最终结果,该函数可以更有效地处理时间计算。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2941  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1803  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   31  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   31  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   28  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用