问题
I have a graph I am trying to filter for a report by day of week. For instance, I wish to find all the instances where they occurred on a Tuesday. Is there a way to either format the datetime field into day of week or filter by day of week directly on the datetime field?
回答1:
You can also determine the day of week in standard SPARQL if you provided a bit of background knowledge. The query needs a reference date preceding your dates and the day of week at this date.
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?date ?dayName
WHERE {
# Sample dates
VALUES ?date {
"1961-08-04"^^xsd:date
"1986-04-03"^^xsd:date
}
# Compute days since a reference date
# This works in Virtuoso, which returns the difference in days.
# For example, Fuseki returns xsd:duration instead.
BIND (?date - "1900-01-01"^^xsd:date AS ?days)
# Compute modulo by 7 without a modulo operator
BIND (floor(?days - (7 * floor(?days/7))) AS ?mod)
VALUES (?mod ?dayName) {
(0 "Monday") # 1900-01-01 was Monday
(6 "Tuesday")
(5 "Wednesday")
(4 "Thursday")
(3 "Friday")
(2 "Saturday")
(1 "Sunday")
}
}
回答2:
SPARQL does not have a 'day of week' function built-in, however, most programming languages have built-in support for retrieving day of week from a given calendar/date object. For example, using Java and RDF4J, you could simply retrieve the dateTime literal (represented as a Literal
object with xsd:dateTime
datatype), convert to a Java calendar object, and then retrieve the weekday:
Literal value = ... ; // the RDF4J literal value from your query result
Calendar calendar = value.calendarValue().toGregorianCalendar();
int weekday = calendar.get(Calendar.DAY_OF_WEEK);
In addition, most SPARQL engines offer the option of adding custom functions.
So you can either just retrieve the dateTime and post-process the result to get the day of the week, or you can actually create a custom function and add it to your SPARQL engine. Here's a tutorial on how to add a custom function to SPARQL using Sesame/RDF4J.
回答3:
SPARQL doesn't have a name-of-day function, but if your SPARQL endpoint is a Virtuoso instance, you can leverage its SQL functions. Here's a query you can run against DBpedia --
SELECT
?birthdate
( bif:dayname(?birthdate) AS ?dayname )
WHERE
{ <http://dbpedia.org/resource/Barack_Obama>
<http://dbpedia.org/ontology/birthDate> ?birthdate
}
-- which will get Barack Obama's birthdate and day --
birthdate dayname
1961-08-04 Friday
I'm thinking it was more the lack of such a function that was blocking you, than not knowing how to build your SPARQL FILTER
?
(ObDisclaimer: OpenLink Software produces Virtuoso, and employs me.)
回答4:
I used Jindrich's solution and tried to refactor it using xsd:duration
arithmetics (which follows the SPARQL and XPath specs, unlike Virtuoso):
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?date ?dayName
WHERE {
# Sample dates
VALUES ?date {
"1961-08-04"^^xsd:date
"1986-04-03"^^xsd:date
}
BIND (xsd:date(?date) - "1900-01-01"^^xsd:date AS ?days)
BIND (?days - (xsd:dayTimeDuration("P7D") * floor(?days / xsd:dayTimeDuration("P7D"))) AS ?mod)
BIND (str(?mod) AS ?modStr)
VALUES (?modStr ?dayName) {
("PT0S" "Monday") # 1900-01-01 was Monday
("P1D" "Tuesday")
("P2D" "Wednesday")
("P3D" "Thursday")
("P4D" "Friday")
("P5D" "Saturday")
("P6D" "Sunday")
}
}
I ran the query on Dydra and I get the right results for the sample dates (Friday and Thursday), but haven't tested further than that.
回答5:
The solution also works with Virtuoso as per this SPARQL Results Page Link.
回答6:
Currently, the initial solution works re. Virtuoso as per this SPARQL Results Page.
Basically, the original response:
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?date ?dayName
WHERE {
# Sample dates
VALUES ?date {
"1961-08-04"^^xsd:date
"1986-04-03"^^xsd:date
}
# Compute days since a reference date
# This works in Virtuoso, which returns the difference in days.
# For example, Fuseki returns xsd:duration instead.
BIND (?date - "1900-01-01"^^xsd:date AS ?days)
# Compute modulo by 7 without a modulo operator
BIND (floor(?days - (7 * floor(?days/7))) AS ?mod)
VALUES (?mod ?dayName) {
(0 "Monday") # 1900-01-01 was Monday
(6 "Tuesday")
(5 "Wednesday")
(4 "Thursday")
(3 "Friday")
(2 "Saturday")
(1 "Sunday")
}
}
# Catch occurrence of any cartesian product that can trick the human eye by adding ORDER BY CLAUSE
ORDER BY DESC
回答7:
Here is a revision that produces the correct solution by applying a pragma for disabling the query optimizer.
DEFINE sql:disable-optimizations 16
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?date ?dayName
WHERE {
# Sample dates
VALUES ?date {
"1961-08-04"^^xsd:date
"1986-04-03"^^xsd:date
}
BIND (xsd:date(?date) - "1900-01-01"^^xsd:date AS ?days)
BIND (bif:mod (?days, xsd:dayTimeDuration("P7D")) AS ?mod)
VALUES (?mod ?dayName) {
("PT0S"^^xsd:dayTimeDuration "Monday") # 1900-01-01 was Monday
("P1D"^^xsd:dayTimeDuration "Tuesday")
("P2D"^^xsd:dayTimeDuration "Wednesday")
("P3D"^^xsd:dayTimeDuration "Thursday")
("P4D"^^xsd:dayTimeDuration "Friday")
("P5D"^^xsd:dayTimeDuration "Saturday")
("P6D"^^xsd:dayTimeDuration "Sunday")
}
}
ORDER BY DESC (?date)
SPARQL Query Results Page
来源:https://stackoverflow.com/questions/41729208/determining-day-of-week-for-datetime-in-sparql