MiniQuark
MiniQuark

Reputation: 48456

In SparQL, how to distinguish a year like 2017, and January 1st, 2017?

The following SPARQL queries using Wikidata's REST API both return a date, of type xsd:datetime, on January 1st:

>>> # Inception of Manchester United F.C. = in 1875
>>> wikidata_rest_query("SELECT ?date WHERE { wd:Q18656 wdt:P571 ?date }")
{'head': {'vars': ['date']},
 'results': {'bindings': [{'date': {'datatype': 'http://www.w3.org/2001/XMLSchema#dateTime',
     'type': 'literal',
     'value': '1875-01-01T00:00:00Z'}}]}}

>>> # Istanbul nightclub attack = on January 1st 2017
>>> wikidata_rest_query("SELECT ?date WHERE { wd:Q28094271 wdt:P585 ?date }")
{'head': {'vars': ['date']},
 'results': {'bindings': [{'date': {'datatype': 'http://www.w3.org/2001/XMLSchema#dateTime',
     'type': 'literal',
     'value': '2017-01-01T00:00:00Z'}}]}}

In the first case, the date just means "in 1875", not literally on January 1st 1875 at midnight. In the second case, the date actually means "on January 1st 2017", but not specifically at midnight. I would have preferred responses like "1875" and "2017-01-01".

When browsing the Wikidata pages for these topics (Manchester United F.C. and 2017 Istanbul Night Club Attack), the correct level of detail is displayed (i.e., 1875 in the first case, but January 1st, 2017 in the second), so they must have the correct information in their database, and hopefully there is a way to query it.

Any ideas?

Note

I tried querying datatype(?date), hoping to see a difference, but it returns xsd:datetime in both examples.

Edit

Here's the python 3 code of wikidata_rest_query(), if you want to test the queries above:

from urllib.request import urlopen, quote
import json

def wikidata_rest_query(query):
    url = "https://query.wikidata.org/sparql?query=%s&format=json" % quote(query)
    with urlopen(url) as f:
        response = f.read().decode("utf-8")
    return json.loads(response)

Upvotes: 3

Views: 329

Answers (1)

MiniQuark
MiniQuark

Reputation: 48456

Wikidata solved this problem by storing additional information about each xsd:datetime, in particular the timePrecision:

>>> query = """
... SELECT ?time ?timeprecision ?timezone ?timecalendar WHERE {
...     wd:Q18656 p:P571/psv:P571 ?timenode.
...     ?timenode wikibase:timeValue         ?time.
...     ?timenode wikibase:timePrecision     ?timeprecision.
...     ?timenode wikibase:timeTimezone      ?timezone.
...     ?timenode wikibase:timeCalendarModel ?timecalendar.
... }
... """
>>> wikidata_rest_query(query)
{'head': {'vars': ['time', 'timeprecision', 'timezone', 'timecalendar']},
 'results': {'bindings': [{'time': {'datatype': 'http://www.w3.org/2001/XMLSchema#dateTime',
     'type': 'literal',
     'value': '1875-01-01T00:00:00Z'},
    'timecalendar': {'type': 'uri',
     'value': 'http://www.wikidata.org/entity/Q1985727'},
    'timeprecision': {'datatype': 'http://www.w3.org/2001/XMLSchema#integer',
     'type': 'literal',
     'value': '9'},
    'timezone': {'datatype': 'http://www.w3.org/2001/XMLSchema#integer',
     'type': 'literal',
     'value': '0'}}]}}

The timePrecision is equal to 9, which means year. The other possible precisions are listed here:

The codes for precision are 0: billion years, 1: hundred million years, 3: million years, 4: hundred thousand years, 5: ten thousand years, 6: millennium, 7: century, 8: decade, 9: year, 10: month, 11: day, 12: hour, 13: minute, 14: second.

If you try the Istanbul query, you will get a timePrecision equal to 11: day, as expected.

It would sure be simpler if we could just write timePrecision(?date), but that's life, and at least we have a solution.

Upvotes: 4

Related Questions