tzrules.n3 7.63 KB
@prefix dc: <http://purl.org/dc/elements/1.1/>.

<> 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    : <tzrules#>.
@prefix tzr: <tzrules#>.

@prefix k: <http://opencyc.sourceforge.net/daml/cyc.daml#>.
@prefix ical: <http://www.w3.org/2002/12/cal/ical#>.

#http://www.w3.org/TR/xmlschema-2/
@prefix dt: <http://www.w3.org/2001/XMLSchema#> .

<> dc:source <http://www.ludd.luth.se/~ams/djgpp/cvs/djgpp/zoneinfo/src/theory>.

<http://www.ludd.luth.se/~ams/djgpp/cvs/djgpp/zoneinfo/src/theory>
 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: <http://www.w3.org/2000/10/swap/log#> .
@prefix str: <http://www.w3.org/2000/10/swap/string#> .
@prefix time: <http://www.w3.org/2000/10/swap/time#>.
@prefix math: <http://www.w3.org/2000/10/swap/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 
  <http://lists.w3.org/Archives/Public/www-rdf-calendar/2003Mar/0022.html>,
  <http://www.w3.org/mid/BKELLDAGKABIOCHDFDBPIEJCCDAA.danny666@virgilio.it>,
  <http://www.codeproject.com/datetime/easter.asp>,
  <http://www.codeproject.com/datetime/easter.asp>,
  <http://www.hourworld.com/easter.htm>.

[ :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 ] }.