Python中维基数据api的日期比较



我想在维基数据API给出的日期之间进行日期比较。

起初我虽然使用 Python 的日期时间模块,但我遇到了两个问题:

  • 维基数据处理儒略历和公历中过去或未来跨越数十亿年的日期,日期时间仅适用于 1 年到 9999 年之间的公历日期。
  • 当精度为 (9) 年或更低时,月份和日期将呈现为"00-00",datetime.strptime 无法管理。

例如,在有关巴黎的示例查询中,可以将此日期转换为日期时间:

datetime.strptime("+1968-01-01T00:00:00Z","+%Y-%m-%dT%H:%M:%SZ")
datetime.datetime(1968, 1, 1, 0, 0)

这个不能:

datetime.strptime("+2012-00-00T00:00:00Z","+%Y-%m-%dT%H:%M:%SZ")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/_strptime.py", line 510, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.5/_strptime.py", line 343, in _strptime
(data_string, format))
ValueError: time data '+2012-00-00T00:00:00Z' does not match format '+%Y-%m-%dT%H:%M:%SZ'

更不用说"-0300-00-00T00:00:00Z"(公元前 300 年)

我不能简单地使用年份比较,因为对于有关共同时代之前发生的事情的项目,在同一负年份中可以有多个日期。

我不太确定处理这个问题的最佳方法。我可以使用另一个库吗?

tl;DR:日期时间不能处理这种事情,所以甚至不要尝试。你有字符串,保留它们并这样对待它们。

您可以简单地将它们排序为字符串,前提是它们的长度一致(否则根据需要填充)和格式。这将允许对">扩展"的 ISO8601:2004 时间戳进行排序(按照标准00不允许对月份和天数进行排序)。

假设 Python3,这段代码:

import urllib.request,json
url = urllib.request.urlopen("https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&ids=Q90&props=info%7Caliases%7Clabels%7Cdescriptions%7Cclaims%7Cdatatype%7Csitelinks%2Furls&languages=fr&languagefallback=1&formatversion=2")
data = json.loads(url.read().decode())
P6 = sorted(data['entities']['Q90']['claims']['P6'], key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'])
for x in P6:
print(x['mainsnak']['datavalue']['value']['numeric-id'])

产生以下结果集:

1685301
947901
656015
2596877
3131449
1986521
1685102
1684642
601266
677730
289303
959708
2105
1685859
256294
2851133

此外,您需要将列表分为两个:

  • -符号开头的项目
  • +符号开头的项目

然后按月-日期-时间升序对第一个列表进行排序,然后按字符串表示的年份的无符号整数值排序(因为sort()sorted()保证"稳定">),简单地对第二个列表进行排序,然后再次将它们连接起来。这将允许对签名ISO8601时间戳进行正确排序。

neg = [x for x in P6 if x['qualifiers']['P580'][0]['datavalue']['value']['time'].startswith('-') ]
pos = [x for x in P6 if x['qualifiers']['P580'][0]['datavalue']['value']['time'].startswith('+') ]
neg.sort(key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'][5:])
neg.sort(key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'][1:5])
pos.sort(key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'])
P6sorted = neg+pos

至于填充,如果需要,使用string.rjust()就足够微不足道了(尽管您必须稍微更改排序以反映"新"时间戳的长度;string.zfill()不是该工作的正确工具,因为您要更改的字符串不是数字,具有"T"、"Z"、"-"和":"):

maxlength = max( map( lambda claim: len( claim['qualifiers']['P580'][0]['datavalue']['value']['time'] ), P6 ) )
for claim in P6:
claim['qualifiers']['P580'][0]['datavalue']['value']['time'] = claim['qualifiers']['P580'][0]['datavalue']['value']['time'][0] + claim['qualifiers']['P580'][0]['datavalue']['value']['time'][1:].rjust(maxlength-1, "0");
neg = [x for x in P6 if x['qualifiers']['P580'][0]['datavalue']['value']['time'].startswith('-') ]
pos = [x for x in P6 if x['qualifiers']['P580'][0]['datavalue']['value']['time'].startswith('+') ]
neg.sort(key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'][maxlength-16:])
neg.sort(key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'][maxlength-22:maxlength-16], reverse=True)
pos.sort(key=lambda claim: claim['qualifiers']['P580'][0]['datavalue']['value']['time'])
P6sorted = neg+pos
for claim in P6sorted:
print([claim['mainsnak']['datavalue']['value']['id'],claim['qualifiers']['P580'][0]['datavalue']['value']['time']])

顺便说一句,为了可读性,您可能需要">装饰-排序-未装饰"(执行施瓦茨变换)。

最后,如果您担心儒略历与公历,则必须通过添加相应的天数,根据国家和年份将儒略日期转换为公历日期,并应用上述方法。但请记住,儒略日期 (YYYY)-(MM)-(DD) 早于"似乎提前一天"的公历日期,因此真的不应该太担心。

相关内容

  • 没有找到相关文章

最新更新