Django函数parse_duration()无法解析年份或月份

时间:2018-04-02 16:42:38

标签: django timedelta

我正在尝试使用P1Y模块的P1M函数分析ISO 8601持续时间parse_duration()django.utils.dateparse,分别代表一年或一个月。但返回的值为None。该函数的文档说它支持ISO 8601持续时间。但似乎它支持标准而没有数年或数月,因为我可以成功解析持续时间P2DT12H60M33S,导致timedelta对象为2天和46833秒。这是一个错误,一个功能还是我做错了什么?

1 个答案:

答案 0 :(得分:0)

来自dateparse.py模块的源代码:

# Support the sections of ISO 8601 date representation that are accepted by
# timedelta
iso8601_duration_re = re.compile(
    r'^(?P<sign>[-+]?)'
    r'P'
    r'(?:(?P<days>\d+(.\d+)?)D)?'
    r'(?:T'
    r'(?:(?P<hours>\d+(.\d+)?)H)?'
    r'(?:(?P<minutes>\d+(.\d+)?)M)?'
    r'(?:(?P<seconds>\d+(.\d+)?)S)?'
    r')?'
    r'$'
)

# Support PostgreSQL's day-time interval format, e.g. "3 days 04:05:06". The
# year-month and mixed intervals cannot be converted to a timedelta and thus
# aren't accepted.
postgres_interval_re = re.compile(
    r'^'
    r'(?:(?P<days>-?\d+) (days? ?))?'
    r'(?:(?P<sign>[-+])?'
    r'(?P<hours>\d+):'
    r'(?P<minutes>\d\d):'
    r'(?P<seconds>\d\d)'
    r'(?:\.(?P<microseconds>\d{1,6}))?'
    r')?$'
)

第一个正则表达式用于解析ISO 8601持续时间。正如iso8601_duration_re上面的评论所述,仅支持timedelta接受的ISO 8601持续时间部分。 timedelta仅支持周,日,小时,分钟,秒,毫秒微秒的位置。 postgres_interval_re

上方的评论中也明确说明了这一点
  

年 - 月和混合间隔不能转换为timedelta,因此不被接受。

通过检查源代码也可以证明不支持数年或数月的事实。例如,iso8601_duration_re正则表达式的代码仅包含天,小时,分钟的解析说明。几年或几个月都没有说明。

我认为有理由不支持数月和数年,因为它们的持续时间不明确。一个月可以是 28,29,30 31 天,一年可以是 365 366 天。 ISO 8601允许这种歧义,但timedelta对象中不允许这种歧义(参见this answer)。这是因为在内部它会将持续时间存储在天,秒微秒(请参阅here),因此<{1>} 1年例如,可以是 365天,0秒 0微秒 366天,0秒 0微秒