【问题标题】:Django function parse_duration() cannot parse years or monthsDjango 函数 parse_duration() 无法解析年或月
【发布时间】:2018-04-02 16:42:38
【问题描述】:

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

【问题讨论】:

    标签: django timedelta


    【解决方案1】:

    来自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上方的评论中也有明确说明:

    年月和混合间隔不能转换为时间增量,因此不被接受。

    不支持年或月的事实,也可以通过查看源代码来证明。例如,iso8601_duration_re 正则表达式的代码只有天、小时、分钟的解析指令。几年或几个月都没有说明。

    我认为不支持几个月和几年是有原因的,因为它们的持续时间不明确。一个月可以是 28,29,3031 天,一年可以是 365366天。这种歧义在 ISO 8601 中是允许的,但在 timedelta 对象中是不允许的(参见 this answer)。这是因为它在内部以 天、秒微秒 为单位存储持续时间(参见 here),因此 1 年timedelta例如,可以是 365 天 0 秒0 微秒366 天 0 秒0 微秒 em>。

    【讨论】:

    • 一天也可以是 23 或 25 小时,如果是闰秒,一分钟可以是 60 或 61 秒。这只是懒惰的设计。
    猜你喜欢
    • 1970-01-01
    • 2021-07-05
    • 2022-10-14
    • 1970-01-01
    • 2020-04-19
    • 2017-04-28
    • 2013-10-04
    • 2023-02-08
    • 2012-07-25
    相关资源
    最近更新 更多