@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 ] }.