SolidLabResearch / Solid-Agent

A rule-based intelligent software agent
8 stars 1 forks source link

Proper calulation of datetime of duration #13

Open woutslabbinck opened 8 months ago

woutslabbinck commented 8 months ago

https://github.com/SolidLabResearch/Solid-Agent/blob/09b80a71499eec339aa4ded6306953ab0ec02656/rules/usage-control/CronRule.n3#L60-L63

Following part of the rule uses built-ins to calculate a new time for a duration.

However it fails when the duration contains Months or Years (e.g. P1Y2M3DT10H30M^^xsd:duration).

This should be fixed such that everything from duration is handled.

Suggestion, this can maybe even make a backward chaining rule to not reproduce it in multiple parts in the codebase?

Pointer: https://eulersharp.sourceforge.net/2003/03swap/eye-builtins.html

josd commented 8 months ago

It can be done with core math: built-ins like in

@prefix time: <http://www.w3.org/2000/10/swap/time#> .
@prefix math: <http://www.w3.org/2000/10/swap/math#> .
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix : <http://example.org/> .

{ ?duration :cronTime ?time } <= {
    "" time:localTime ?currentTime . # Current time
    (?currentTime ?duration) math:sum ?epoch .
    (?lexval xsd:dateTime) log:dtlit ?epoch . # binds ?lexval
    (?lexval xsd:dateTime) log:dtlit ?time . # binds ?time
} .

and the query

@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix : <http://example.org/> .

{ "P1Y2M3DT10H30M"^^xsd:duration :cronTime ?time } => { "P1Y2M3DT10H30M"^^xsd:duration :cronTime ?time } .

will give

$ eye --quiet --nope cronTime.n3 --query cronTime-query.n3
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix : <http://example.org/>.

"P1Y2M3DT10H30M"^^xsd:duration :cronTime "2024-11-17T03:06:56.306999921Z"^^xsd:dateTime.
josd commented 8 months ago

That said, there is some danger in doing so as each month (and also each year) is not an equal amount of seconds. This is also why there are 3 duration types.

josd commented 8 months ago

There is now an extra func:add-duration-to-dateTime built-in EYE v4.16.2 https://github.com/eyereasoner/eye/commit/ca895f47470229ac0da85dcc6e299e2ee83497d3 This is a small test

$ cat cronTime.n3
@prefix time: <http://www.w3.org/2000/10/swap/time#> .
@prefix func: <http://www.w3.org/2007/rif-builtin-function#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix : <http://example.org/> .

{ ?duration :cronTime ?time } <= {
    "" time:localTime ?currentTime . # Current time
    (?currentTime ?duration) func:add-duration-to-dateTime ?time . # ?time is the time that the cronJob should fire
} .
$ cat cronTime-query.n3
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix : <http://example.org/> .

{ "P1YT10H30M"^^xsd:duration :cronTime ?time } => { "P1YT10H30M"^^xsd:duration :cronTime ?time } .
{ "P2MT10H30M"^^xsd:duration :cronTime ?time } => { "P2MT10H30M"^^xsd:duration :cronTime ?time } .
{ "P3DT10H30M"^^xsd:duration :cronTime ?time } => { "P3DT10H30M"^^xsd:duration :cronTime ?time } .
{ "P1Y2M3DT10H30M"^^xsd:duration :cronTime ?time } => { "P1Y2M3DT10H30M"^^xsd:duration :cronTime ?time } .
$ eye --quiet --nope cronTime.n3 --query cronTime-query.n3
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix : <http://example.org/>.

"P1YT10H30M"^^xsd:duration :cronTime "2024-09-15T10:28:02Z"^^xsd:dateTime.
"P2MT10H30M"^^xsd:duration :cronTime "2023-11-15T10:28:02Z"^^xsd:dateTime.
"P3DT10H30M"^^xsd:duration :cronTime "2023-09-18T10:28:02Z"^^xsd:dateTime.
"P1Y2M3DT10H30M"^^xsd:duration :cronTime "2024-11-18T10:28:02Z"^^xsd:dateTime.
woutslabbinck commented 8 months ago

Wow, nice work. I tested it by also adding the current time and a simple duration:

@prefix time: <http://www.w3.org/2000/10/swap/time#> .
@prefix func: <http://www.w3.org/2007/rif-builtin-function#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix : <http://example.org/> .

{ "P1YT10H30M"^^xsd:duration :cronTime ?time } => { "P1YT10H30M"^^xsd:duration :cronTime ?time } .
{ "P2MT10H30M"^^xsd:duration :cronTime ?time } => { "P2MT10H30M"^^xsd:duration :cronTime ?time } .
{ "P3DT10H30M"^^xsd:duration :cronTime ?time } => { "P3DT10H30M"^^xsd:duration :cronTime ?time } .
{ "P1Y2M3DT10H30M"^^xsd:duration :cronTime ?time } => { "P1Y2M3DT10H30M"^^xsd:duration :cronTime ?time } .
{ "P1Y"^^xsd:duration :cronTime ?time } => { "P1Y"^^xsd:duration :cronTime ?time } .

{ "" time:localTime ?currentTime .} => { :currentTime :is ?currentTime } .

And the output was

@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix : <http://example.org/>.

"P1YT10H30M"^^xsd:duration :cronTime "2024-09-15T20:35:20Z"^^xsd:dateTime.
"P2MT10H30M"^^xsd:duration :cronTime "2023-11-15T20:35:20Z"^^xsd:dateTime.
"P3DT10H30M"^^xsd:duration :cronTime "2023-09-18T20:35:20Z"^^xsd:dateTime.
"P1Y2M3DT10H30M"^^xsd:duration :cronTime "2024-11-18T20:35:20Z"^^xsd:dateTime.
"P1Y"^^xsd:duration :cronTime "2024-09-15T10:05:20Z"^^xsd:dateTime.
:currentTime :is "2023-09-15T10:05:10.272Z"^^xsd:dateTime.

So exactly what I had expected.

I'll wait to add this to the code however until eye-js and koreografeye use EYE v4.16.2.