2017-06-21 13 views
1

我想在維基數據API給出的日期之間進行日期比較。Python中的維基數據日期比較

起初,我雖然使用Python的日期時間模塊,但是我碰到了兩個問題:

  • 維基數據處理跨越了數十億年過去還是在朱利安和公曆將來的日期,日期時間僅適用於年份1至9999之間的公曆日期。
  • 當精度爲(9)年或更低時,月份和日期呈現爲「00-00」,而datetime.strptime不管理該日期。

例如,在此sample query約巴黎,這個日期可以轉換爲日期時間:

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年)

我不能簡單地使用年比較,因爲對於有關發生在普通呃之前的事情的項目a,在同一個負向年份可能有幾個日期。

我不太確定處理這個問題的最佳方法。是否有另一個我可以使用的庫?

+1

你是什麼意思的日期比較? 「+ 2012-00-00T00:00:00Z」和「+ 2012-01-01T00:00:00Z」之間的比較結果是什麼? –

+0

日期是對索賠使用的限定詞。現在,我想要最近的人口,但我希望該方法更通用。 –

回答

2

tl; dr: datetime無法處理那種事情,所以甚至不嘗試。你有字符串,保留它們並像這樣對待它們。

您可以簡單地將它們排序爲字符串,只要它們具有一致的長度(否則根據需要填充)和格式。這將允許排序「擴展」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']) 

產生此ResultSet:

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

此外,您會希望您的名單分成兩個:

  • 項目開始a -標誌
  • 項目用+跡象開始

然後通過一個字符串表示的一年的無符號整型值(排序一個月的日期時間升序第一個列表,然後根據sort()sorted()guaranteedstable ),簡單地排序第二個,並再次連接它們。這將允許簽署 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']]) 

順便說一句,你可能會想「 Decorate-Sort-Undecorate「(執行Schwartzian變換),以提高可讀性。

最後,如果您擔心Julian vs Gregorian日曆,則必須將Julian日期轉換爲基於國家和年份的公曆日期,並添加相應的天數,然後應用上述方法。但要記住Julian的日期(YYYY) - (MM) - (DD)早於格里高利的日期「似乎提前一天」,所以它真的不應該太擔心。