有没有简单的方法将ISO 8601持续时间转换为timedelta?

时间:2016-05-02 06:25:05

标签: python datetime timedelta python-datetime

鉴于ISO 8601持续时间字符串,如何将其转换为datetime.timedelta

这没有用:

timedelta("PT1H5M26S", "T%H%M%S")

4 个答案:

答案 0 :(得分:24)

我发现isodate库正是我想做的

<?php

class DB
{

  public static function connect()
  {
    $hostname = 'localhost';
    $username = 'user';
    $password = 'password';
    $dbName = 'dbname';
    $connection = new mysqli($hostname, $username, $password, $dbName);

  if ($connection->connect_error) {
     die('Failed to connect');
   }

  return $connection;
  }
}

答案 1 :(得分:1)

这是一个没有新软件包的解决方案,但仅在您要处理以天为单位的最大持续时间时才有效。不过,这种限制是有道理的,因为正如其他人指出的那样(1):

鉴于timedelta具有超过“一个月”的天数, 您会使用ISO8601持续时间符号来描述它吗 引用特定时间点?相反,以您的示例为例, “ P3Y6M4DT12H30M5S”,如何将其转换为时间增量 不知道这段持续时间指的是确切的年月。 Timedelta对象是非常精确的野兽,几乎可以肯定 为什么他们不支持“年”和“月”参数 构造函数。

import datetime


def get_isosplit(s, split):
    if split in s:
        n, s = s.split(split)
    else:
        n = 0
    return n, s


def parse_isoduration(s):
        
    # Remove prefix
    s = s.split('P')[-1]
    
    # Step through letter dividers
    days, s = get_isosplit(s, 'D')
    _, s = get_isosplit(s, 'T')
    hours, s = get_isosplit(s, 'H')
    minutes, s = get_isosplit(s, 'M')
    seconds, s = get_isosplit(s, 'S')

    # Convert all to seconds
    dt = datetime.timedelta(days=int(days), hours=int(hours), minutes=int(minutes), seconds=int(seconds))
    return int(dt.total_seconds())
> parse_isoduration("PT1H5M26S")
3926

答案 2 :(得分:0)

好问题,显然“正确”的解决方案取决于您对输入的期望(更可靠的数据源不需要那么多输入验证)。

我解析 ISO8601 持续时间时间戳的方法仅检查“PT”前缀是否存在,并且不会假设任何单位的整数值:

from datetime import timedelta

def parse_isoduration(isostring, as_dict=False):
    """
    Parse the ISO8601 duration string as hours, minutes, seconds
    """
    separators = {
        "PT": None,
        "W": "weeks",
        "D": "days",
        "H": "hours",
        "M": "minutes",
        "S": "seconds",
    }
    duration_vals = {}
    for sep, unit in separators.items():
        partitioned = isostring.partition(sep)
        if partitioned[1] == sep:
            # Matched this unit
            isostring = partitioned[2]
            if sep == "PT":
                continue # Successful prefix match
            dur_str = partitioned[0]
            dur_val = float(dur_str) if "." in dur_str else int(dur_str)
            duration_vals.update({unit: dur_val})
        else:
            if sep == "PT":
                raise ValueError("Missing PT prefix")
            else:
                # No match for this unit: it's absent
                duration_vals.update({unit: 0})
    if as_dict:
        return duration_vals
    else:
        return tuple(duration_vals.values())

dur_isostr = "PT3H2M59.989333S"
dur_tuple = parse_isoduration(dur_isostr)
dur_dict = parse_isoduration(dur_isostr, as_dict=True)
td = timedelta(**dur_dict)
s = td.total_seconds()

>>> dur_tuple
(0, 0, 3, 2, 59.989333)
>>> dur_dict
{'weeks': 0, 'days': 0, 'hours': 3, 'minutes': 2, 'seconds': 59.989333}
>>> td
datetime.timedelta(seconds=10979, microseconds=989333)
>>> s
10979.989333

答案 3 :(得分:0)

基于@r3robertson 一个更完整但不完美的版本

int