如何在Python中解析和比较ISO 8601持续时间?
我在找一个Python(版本2)的库,想用它来解析和比较ISO 8601格式的时间段,这些时间段可能会用不同的单位表示。
最好这个库能支持标准的比较操作,比如用a < b这样的方式,不过如果有类似a.compare(b)的比较方法也可以。
就像这样:
duration('P23M') < duration('P2Y') //True
duration('P25M') < duration('P2Y') //False
我已经从PyPi安装了isodate这个库,但它有自己的一套处理时间段的方式,包括月份和年份,而这些时间段之间不能直接比较,也不能和timedelta(时间差)比较。
3 个回答
1
面对同样的问题,我使用了正则表达式来解析时间段,并比较得到的秒数:
def duration(duration_str):
match = re.match(
r'P((?P<years>\d+)Y)?((?P<months>\d+)M)?((?P<weeks>\d+)W)?((?P<days>\d+)D)?(T((?P<hours>\d+)H)?((?P<minutes>\d+)M)?((?P<seconds>\d+)S)?)?',
duration_str
).groupdict()
return int(match['years'] or 0)*365*24*3600 + \
int(match['months'] or 0)*30*24*3600 + \
int(match['weeks'] or 0)*7*24*3600 + \
int(match['days'] or 0)*24*3600 + \
int(match['hours'] or 0)*3600 + \
int(match['minutes'] or 0)*60 + \
int(match['seconds'] or 0)
请注意,这里默认一年是365天,一个月是30天,等等。
9
这里对时间的计算做了一些简单处理(一个月算30天,一年算平均值等等):
# parse 8601 duration
from re import findall
def iso8601_duration_as_seconds( d ):
if d[0] != 'P':
raise ValueError('Not an ISO 8601 Duration string')
seconds = 0
# split by the 'T'
for i, item in enumerate(d.split('T')):
for number, unit in findall( '(?P<number>\d+)(?P<period>S|M|H|D|W|Y)', item ):
# print '%s -> %s %s' % (d, number, unit )
number = int(number)
this = 0
if unit == 'Y':
this = number * 31557600 # 365.25
elif unit == 'W':
this = number * 604800
elif unit == 'D':
this = number * 86400
elif unit == 'H':
this = number * 3600
elif unit == 'M':
# ambiguity ellivated with index i
if i == 0:
this = number * 2678400 # assume 30 days
# print "MONTH!"
else:
this = number * 60
elif unit == 'S':
this = number
seconds = seconds + this
return seconds
for d in [ 'PT10M', 'PT5H', 'P3D', 'PT45S', 'P8W', 'P7Y', 'PT5H10M', 'P2YT3H10M', 'P3Y6M4DT12H30M5S', 'P23M', 'P2Y' ]:
seconds = iso8601_duration_as_seconds( d )
print "%s \t= %s" % (d,seconds)
print
print '%s' % (iso8601_duration_as_seconds('P23M') < iso8601_duration_as_seconds('P2Y') )
# True
print '%s' % (iso8601_duration_as_seconds('P25M') < iso8601_duration_as_seconds('P2Y') )
# False
3
我最后“解决”这个问题的方法是,把加上时间段后的值和当前的UTC时间进行比较。当然,这意味着在二月份,P30D(30天)会比P1M(1个月)长,而在三月份则会短,四月份时两者是相等的。这并不是最理想的解决办法,但对我来说已经足够用了。