Determining Day Of Week For Datetime in SPARQL

梦想与她 提交于 2020-06-27 17:45:09

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!