@prefix dc: .
<> dc:description """
some timezone and recurrence rules:
* figure Z-time of Vevents from local time and timezone info, in
* limited cases.
* relate URIs such as
http://www.w3.org/2002/12/cal/tzd/America/Chicago#tz
to geographical regions Chicago and America
* find out if dateTimes intersect weekly recurring events
(the business hours case)
* compute the month and day of easter in any given year
""",
"$Id: tzrules.n3,v 1.4 2003/03/14 16:39:50 connolly Exp $".
@prefix : .
@prefix tzr: .
@prefix k: .
@prefix ical: .
#http://www.w3.org/TR/xmlschema-2/
@prefix dt: .
<> dc:source .
dc:description # excerpt, actually...
"""
Names normally have the form AREA/LOCATION, where AREA is the name
of a continent or ocean, and LOCATION is the name of a specific
location within that region. North and South America share the same
area, `America'. Typical names are `Africa/Cairo', `America/New_York',
and `Pacific/Honolulu'.
""".
[ k:nameString "America";
k:geographicalSubRegions [ k:nameString "Chicago" ] ].
@prefix log: .
@prefix str: .
@prefix time: .
@prefix math: .
this log:forAll :TZ.
{
?LOCATION k:nameString ?LOCATION_N;
is k:geographicalSubRegions of [ k:nameString ?AREA_N].
?TZN is str:concatenation of (
"http://www.w3.org/2002/12/cal/tzd/" ?AREA_N "/" ?LOCATION_N "#tz" ).
:TZ log:uri ?TZN.
[ is log:racine of :TZ ] log:semantics [ log:includes {
:TZ a ical:Vtimezone } ].
}
log:implies {
:TZ a ical:Vtimezone.
?LOCATION :timeZone :TZ.
}.
# convert ical dateTime/tzid to Z-time, in limited cases:
# RRULE has freq YEARLY
# DST
# month not on boundary
# first, find offset for a whole month...
{
?TZ ical:tzid ?TZID;
ical:standard [
ical:rrule [ ical:freq "YEARLY"; ical:bymonth ?SMO ];
ical:tzoffsetto ?STZTO
];
ical:daylight [
ical:rrule [ ical:freq "YEARLY"; ical:bymonth ?DMO ];
ical:tzoffsetto ?DTZTO
].
# month of ?DT within daylight time?
#only works if ?SMO > ?DMO
#We leave the edge-month cases alone for now...
[ ical:dateTime [ time:month ?M ] ]. #@@hmm...
?M
math:greaterThan ?DMO;
math:lessThan ?SMO.
?DOFFSECS is math:product of ( ?DTZTO "0.01" "3600" ). # only works for whole hours
} =>
{ ?TZ :offsetDuring [ :monthNum ?M; :offset ?DOFFSECS ] }.
{
?TZ ical:tzid ?TZID;
:offsetDuring [ :monthNum ?M; :offset ?DOFFSECS ].
?WHEN ical:dateTime ?DT; ical:tzid ?TZID.
?DT time:month ?M.
[ is str:concatenation of (?DT "Z")] time:inSeconds ?DTSECS.
?UT time:inSeconds [ is math:sum of ( ?DTSECS ?DOFFSECS ) ].
} => { ?WHEN dt:dateTime ?UT }.
#######
#
# business hours usecase...
#
# is the business open at time ?WHEN ?
#
:exampleTime1 dt:dateTime "2003-06-13T22:00:00Z".
:exampleTime2 ical:dateTime "2003-05-13T22:00:00";
ical:tzid "/softwarestudio.org/Olson_20011030_5/America/New_York".
:exampleTime3 ical:dateTime "2003-06-13T22:00:00";
ical:tzid "/softwarestudio.org/Olson_20011030_5/America/Chicago".
# relate cyc's day of week types to
# time:dayOfWeek indexes and to
# ical abbreviations
# hmm... move this to a week.rdf KB?
k:Sunday :index "0"; :dayAbbr "SU".
k:Monday :index "1"; :dayAbbr "MO".
k:Tuesday :index "2"; :dayAbbr "TU".
k:Wednesday :index "3"; :dayAbbr "WE".
k:Thursday :index "4"; :dayAbbr "TH".
k:Friday :index "5"; :dayAbbr "FR".
k:Saturday :index "6"; :dayAbbr "SA".
# Turn Z time into, say, Monday 10:35 Chicago time
# based the fact that Chicago is -0600 during June.
{
?WHEN dt:dateTime ?UT.
?UT time:month ?M.
?TZ :offsetDuring [ :monthNum ?M; :offset ?DOFFSECS ].
(?DOFFSECS [ is time:inSeconds of ?UT ]) math:sum ?LTSECS.
?LT time:inSeconds ?LTSECS.
?LT time:dayOfWeek [ is :index of ?DOW ];
time:hour ?HH; time:minute ?MM.
} => { ?WHEN :localTime [ :tz ?TZ; :dow ?DOW; :hh ?HH; :mm ?MM ] }.
# Now compare Monday 10:35 Chicago time
# with the shop hours for Monday...
{
?WHEN :localTime [ :tz ?TZ; :dow ?DOW; :hh ?HH; :mm ?MM ].
?TZ ical:tzid ?TZID.
?E
ical:dtstart [
ical:tzid ?TZID;
ical:dateTime [
time:hour ?START_HH;
time:minute ?START_MM;
];
];
ical:dtend [
ical:tzid ?TZID;
ical:dateTime [
time:hour ?END_HH;
time:minute ?END_MM;
];
];
ical:rrule [ ical:freq "WEEKLY"; ical:interval "1";
ical:byday [ str:contains [ is :dayAbbr of ?DOW ] ] ].
[ is str:concatenation of (?HH ?MM) ]
str:notLessThan [ is str:concatenation of (?START_HH ?START_MM) ];
str:notGreaterThan [ is str:concatenation of (?END_HH ?END_MM) ];
}
=> { ?WHEN k:temporallyIntersects ?E }.
####
#
# when is easter this year?
#
<> dc:source
,
,
,
,
.
[ :startYear "0"; :endYear "1700"; :easterCorrection "4"].
[ :startYear "1700"; :endYear "1800"; :easterCorrection "5"].
[ :startYear "1800"; :endYear "1900"; :easterCorrection "6"].
[ :startYear "1900"; :endYear "2100"; :easterCorrection "0"].
[ :startYear "2100"; :endYear "2200"; :easterCorrection "1"].
[ :startYear "2200"; :endYear "2300"; :easterCorrection "2"].
[ :startYear "2300"; :endYear "2500"; :easterCorrection "3"].
# some test data...
:DansBirthDay dt:date "1967-12-09".
:USIndependenceDay dt:date "1776-07-04".
# discover that various years exist...
# called k:TheYearNNNN
{ [ dt:date [ time:year ?YYYY ]].
?I is str:concatenation of (
"http://opencyc.sourceforge.net/daml/cyc.daml#TheYear"
?YYYY
).
?YEAR log:uri ?I.
}
=>
{
?YEAR a k:CalendarYear;
dt:gYear ?YYYY;
is k:YearFn of [ dt:integer ?YYYY ]
}.
# relate them to dates
{ ?WHEN dt:date [ time:year ?YYYY ].
?YEAR dt:gYear ?YYYY.
} => { ?YEAR k:temporallySubsumes ?WHEN }.
# now find easter on each such year...
{
?WHEN dt:gYear ?YYYY.
[ :startYear [ str:notGreaterThan ?YYYY ];
:endYear [ str:greaterThan ?YYYY ];
:easterCorrection ?C ].
?wDay is math:remainder of (
[ is math:sum of (
[ is math:product of (
"19"
[ is math:remainder of (?YYYY "19")]
)]
"24"
)]
"30").
?wDay2 is math:sum of (
"22"
?wDay
[ is math:remainder of (
[ is math:sum of (
[ is math:product of (
"2"
[is math:remainder of (?YYYY "4")]
)]
[ is math:product of ("4" [is math:remainder of (?YYYY "7")])]
[ is math:product of ("6" ?wDay)]
"5"
?C
)]
"7"
)]
).
} => { ?WHEN :easterStep1 ?wDay2 }.
{
?WHEN :easterStep1 ?wDay.
?wDay math:greaterThan "31".
?wDay2 is math:difference of ( ?wDay "31").
}
=> { ?WHEN :easterDay ?wDay2; :easterMonth "04" }.
{
?WHEN :easterStep1 ?wDay.
?wDay math:notGreaterThan "31".
}
=> { ?WHEN :easterDay ?wDay; :easterMonth "03" }.
# now put it all together...
{
?WHEN dt:gYear ?YYYY; :easterDay ?D; :easterMonth ?MM.
# prepend "0" then take last 2 chars
?DD is str:scrape of ([ is str:concatenation of ("0" ?D) ] "(..)$").
?YMD is str:concatenation of (?YYYY "-" ?MM "-" ?DD ).
}
=> { ?WHEN k:temporallySubsumes [ a :EasterHoliday; dt:date ?YMD ] }.