a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
9eaf1d2008-06-28Martin Nilsson protected constant M_YD=({0,0,31,59,90,120,151,181,212,243,273,304,334}); protected constant M_ED=({({0,31,59,90,120,151,181,212,243,273,304,334,365}),
ac8c922003-03-12Martin Nilsson  ({0,31,60,91,121,152,182,213,244,274,305,335,366}), ({0,31,60,90,120,151,181,212,243,273,304,334,365}) });
9eaf1d2008-06-28Martin Nilsson protected constant M_NAME="---JanFebMarAprMayJunJulAugSepOctNovDec"/3; protected constant WD_NAME="---MonTueWedThuFriSatSun"/3;
78fd532000-07-12Mirar (Pontus Hagland) 
9eaf1d2008-06-28Martin Nilsson protected function(mixed...:Calendar.TimeRanges.TimeRange) std_day=
9f0b6c2008-02-07Martin Stjernholm  Calendar.Day;
9eaf1d2008-06-28Martin Nilsson protected function(mixed...:Calendar.TimeRanges.TimeRange) std_second=
9f0b6c2008-02-07Martin Stjernholm  Calendar.Second;
0332d82000-10-26Mirar (Pontus Hagland) 
78fd532000-07-12Mirar (Pontus Hagland) // ---------------------------------------------------------------- // base classes // ----------------------------------------------------------------
ac8c922003-03-12Martin Nilsson //! Event is an abstract class, defining what methods an Event //! need to have.
78fd532000-07-12Mirar (Pontus Hagland) class Event { string name;
68e10f2000-09-07Mirar (Pontus Hagland)  string id="?";
78fd532000-07-12Mirar (Pontus Hagland) 
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify an event object.
78fd532000-07-12Mirar (Pontus Hagland)  constant is_event=1;
ac8c922003-03-12Martin Nilsson  //! This calculates the next or previous occurance of the event, //! from the given timerange's start, including any event occuring //! at the start if that flag is set. //! //! It returns zero if there is no next event. //! //! These methods are virtual in the base class.
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including); Calendar.TimeRanges.TimeRange previous(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including);
ac8c922003-03-12Martin Nilsson  //! This calculates the eventual events that is contained or //! overlapped by the given timerange. @[scan] uses @[next], if not //! overloaded. //! //! @example
6201ce2003-05-04Martin Nilsson  //! Calendar.Event.Easter()->scan(Calendar.Year(2000)) //! => ({ Day(Sun 23 Apr 2000) })
ac8c922003-03-12Martin Nilsson  //! //! @note //! @[scan] can return an array of overlapping timeranges. //! //! This method must use @tt{in->calendar_object->@}@i{type@} //! to create the returned timeranges, and must keep the ruleset.
9f0b6c2008-02-07Martin Stjernholm  array(Calendar.TimeRanges.TimeRange) scan(Calendar.TimeRanges.TimeRange in)
ac8c922003-03-12Martin Nilsson  {
78fd532000-07-12Mirar (Pontus Hagland)  array res=({});
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange t=next(in,1);
78fd532000-07-12Mirar (Pontus Hagland)  for (;;) { if (!t || !t->overlaps(in)) return res; res+=({t}); t=next(t); }
ac8c922003-03-12Martin Nilsson  }
78fd532000-07-12Mirar (Pontus Hagland) 
ac8c922003-03-12Martin Nilsson  //! Returns a mapping with time ranges mapped to events.
9f0b6c2008-02-07Martin Stjernholm  mapping(Calendar.TimeRanges.TimeRange:Event) scan_events(Calendar.TimeRanges.TimeRange in)
ac8c922003-03-12Martin Nilsson  { array r=scan(in);
563bd72004-01-11Martin Nilsson  return mkmapping(r,allocate(sizeof(r),this));
ac8c922003-03-12Martin Nilsson  }
78fd532000-07-12Mirar (Pontus Hagland) 
ac8c922003-03-12Martin Nilsson  //! Joins several events into one @[SuperEvent]. SuperEvent `|(Event ... with)
78fd532000-07-12Mirar (Pontus Hagland)  { with-=({0});
563bd72004-01-11Martin Nilsson  with|=({this});
78fd532000-07-12Mirar (Pontus Hagland)  if (sizeof(with)==1) return with[0]; return SuperEvent(with); }
ac8c922003-03-12Martin Nilsson  SuperEvent ``|(Event with) { return `|(with); }
78fd532000-07-12Mirar (Pontus Hagland)  string _sprintf(int t) {
68e10f2000-09-07Mirar (Pontus Hagland)  return (t!='O')?0:sprintf("Event(%s:%O)",id,name);
78fd532000-07-12Mirar (Pontus Hagland)  } array(Event) cast(string to) { if (to[..4]=="array")
563bd72004-01-11Martin Nilsson  return ({this});
78fd532000-07-12Mirar (Pontus Hagland)  else error("Can't cast to %O\n",to); }
ac8c922003-03-12Martin Nilsson  //! Returns a description of the event.
78fd532000-07-12Mirar (Pontus Hagland)  string describe() { return "Unknown event"; } }
ac8c922003-03-12Martin Nilsson //! A non-event.
78fd532000-07-12Mirar (Pontus Hagland) class NullEvent { inherit Event;
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify a NullEvent.
325f582000-08-06Mirar (Pontus Hagland)  constant is_nullevent=1;
68e10f2000-09-07Mirar (Pontus Hagland)  void create(string _id,string s,mixed ...args) { id=_id; name=s; }
78fd532000-07-12Mirar (Pontus Hagland) 
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  { return 0; }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange previous(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  { return 0; } }
ac8c922003-03-12Martin Nilsson //! @[Day_Event] is an abstract class, extending @[Event] for events //! that are single days, using julian day numbers for the calculations.
78fd532000-07-12Mirar (Pontus Hagland) class Day_Event { inherit Event;
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify @[Day_Event] objects.
78fd532000-07-12Mirar (Pontus Hagland)  constant is_day_event=1;
ac8c922003-03-12Martin Nilsson  //! Returned from @[scan_jd] if the even searched for did not //! exist.
78fd532000-07-12Mirar (Pontus Hagland)  constant NODAY=-1; int nd=1;
9f0b6c2008-02-07Martin Stjernholm  //! @decl int scan_jd(Calendar.Calendar realm, int jd,@
5dc75a2003-03-13Martin Nilsson  //! int(-1..-1)|int(1..1) direction)
48fb2f2012-09-07Henrik Grubbström (Grubba)  //! This method has to be defined, and is what //! really does some work.
ac8c922003-03-12Martin Nilsson  //! //! @param direction //! @int //! @value 1 //! Forward (next), //! @value -1 //! Backward (previous). //! @endint
48fb2f2012-09-07Henrik Grubbström (Grubba)  //! //! @returns //! It should return the next or previous //! julian day (>@i{jd@}) when the event occurs, //! or the constant @[NODAY] if it doesn't.
ac8c922003-03-12Martin Nilsson 
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(1..1)|int(-1..-1) direction);
ac8c922003-03-12Martin Nilsson  //! Uses the virtual method @[scan_jd]. //! @seealso //! @[Event.next]
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  {
0332d82000-10-26Mirar (Pontus Hagland)  if (!from) from=std_day();
45ab4c2000-08-01Mirar (Pontus Hagland)  int jd; if (including) jd=(int)(from->julian_day()); else jd=(int)(from->end()->julian_day()); jd=scan_jd(from->calendar(),jd-nd+1,1);
78fd532000-07-12Mirar (Pontus Hagland)  return (from->calendar()->Day)("julian_r",jd,from->ruleset())*nd; }
ac8c922003-03-12Martin Nilsson  //! Uses the virtual method @[scan_jd]. //! @seealso //! @[Event.previous]
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange previous(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  {
0332d82000-10-26Mirar (Pontus Hagland)  if (!from) from=std_day();
45ab4c2000-08-01Mirar (Pontus Hagland)  int jd; if (including) jd=(int)(from->end()->julian_day()); else jd=(floatp(from->julian_day()) ?(int)floor(from->julian_day()) :(from->julian_day()-1)); jd=scan_jd(from->calendar(),jd+nd-1,-1);
78fd532000-07-12Mirar (Pontus Hagland)  if (jd==NODAY) return 0; return (from->calendar()->Day)("julian_r",jd,from->ruleset())*nd; } }
ac8c922003-03-12Martin Nilsson //! This is created by the @[Namedays] classes //! to represent an event for a name.
78fd532000-07-12Mirar (Pontus Hagland) class Nameday { inherit Day_Event;
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify @[Nameday] objects.
78fd532000-07-12Mirar (Pontus Hagland)  constant is_nameday=1; int jd; void create(string _name,int _jd) { name=_name; jd=_jd; }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int sjd,int(1..1)|int(-1..-1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { if (direction==1) return sjd<=jd?jd:NODAY; else return sjd>=jd?jd:NODAY; } string _sprintf(int t) {
68e10f2000-09-07Mirar (Pontus Hagland)  return t=='O'?sprintf("Nameday(%s:%O)",id,name):0;
78fd532000-07-12Mirar (Pontus Hagland)  } }
ac8c922003-03-12Martin Nilsson //! This contains a ruleset about namedays.
78fd532000-07-12Mirar (Pontus Hagland) class Namedays { inherit Event;
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify @[Namedays].
78fd532000-07-12Mirar (Pontus Hagland)  constant is_namedays=1;
4f7b302000-09-30Mirar (Pontus Hagland)  int leapdayshift; int first_year=-1; int last_year=-1; array namelist; mapping lookup; void create(string _id,string _name, array(array(string)) _names, mapping(string:int|array(int)) _lookup, void|int start,void|int stop,void|int _leapdayshift) { id=_id; name=_name; namelist=_names; first_year=start||-1; last_year=stop||-1; leapdayshift=_leapdayshift||2000; lookup=_lookup; }
ac8c922003-03-12Martin Nilsson  //! Gives back an array of names that occur during //! the time period, in no particular order.
9f0b6c2008-02-07Martin Stjernholm  array(string) names(Calendar.TimeRanges.TimeRange t)
78fd532000-07-12Mirar (Pontus Hagland)  {
ac8c922003-03-12Martin Nilsson  // optimize this?
78fd532000-07-12Mirar (Pontus Hagland)  return predef::`|(({}),@values(namedays(t))); }
ac8c922003-03-12Martin Nilsson  //! Gives back an table of days with names that occur during //! the time period. Note that days without names will not //! appear in the returned mapping.
9f0b6c2008-02-07Martin Stjernholm  mapping(Calendar.TimeRanges.TimeRange:array(string)) namedays(Calendar.TimeRanges.TimeRange t)
78fd532000-07-12Mirar (Pontus Hagland)  { int jd=t->julian_day(); mapping res=([]);
9f0b6c2008-02-07Martin Stjernholm  function(mixed...:Calendar.TimeRanges.TimeRange) day=t->calendar()->Day; Calendar.Ruleset rules=t->ruleset();
78fd532000-07-12Mirar (Pontus Hagland)  [int y,int yjd,int leap]=gregorian_yjd(jd);
4f7b302000-09-30Mirar (Pontus Hagland)  if (first_year!=-1 && y<first_year) [y,yjd,leap]=gregorian_year(first_year),jd=yjd; if (last_year!=-1 && y>last_year) return res;
78fd532000-07-12Mirar (Pontus Hagland)  int ld;
4f7b302000-09-30Mirar (Pontus Hagland)  if (y<leapdayshift) ld=55-1; // 24 feb
78fd532000-07-12Mirar (Pontus Hagland)  else ld=60-1; // 29 feb for (;;) {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange td=day("julian_r",jd,rules);
78fd532000-07-12Mirar (Pontus Hagland)  if (!td->overlaps(t)) return res; if (jd>=yjd+365+leap) // next year { [y,yjd,leap]=gregorian_yjd(jd);
4f7b302000-09-30Mirar (Pontus Hagland)  if (last_year!=-1 && y>last_year) return res; if (y<leapdayshift) ld=55-1; // 24 feb
78fd532000-07-12Mirar (Pontus Hagland)  else ld=60-1; // 29 feb }
4f7b302000-09-30Mirar (Pontus Hagland)  array(string) n; int d=jd-yjd; if (leap) { if (d<ld) n=namelist[d]; else if (d>ld) n=namelist[d-1]; else n=namelist[-1];
78fd532000-07-12Mirar (Pontus Hagland)  } else
4f7b302000-09-30Mirar (Pontus Hagland)  n=namelist[d];
78fd532000-07-12Mirar (Pontus Hagland) 
4f7b302000-09-30Mirar (Pontus Hagland)  if (n) res[td]=n; jd++;
78fd532000-07-12Mirar (Pontus Hagland)  } }
9f0b6c2008-02-07Martin Stjernholm  mapping(Calendar.TimeRanges.TimeRange:Event) scan_events(Calendar.TimeRanges.TimeRange in)
78fd532000-07-12Mirar (Pontus Hagland)  { mapping res=([]);
9f0b6c2008-02-07Martin Stjernholm  foreach ((array)namedays(in), [Calendar.TimeRanges.TimeRange t,array(string) s])
78fd532000-07-12Mirar (Pontus Hagland)  res[t]=predef::`|(@map(s,Nameday,t->julian_day())); return res; }
9f0b6c2008-02-07Martin Stjernholm  array(Calendar.TimeRanges.TimeRange) scan(Calendar.TimeRanges.TimeRange in)
78fd532000-07-12Mirar (Pontus Hagland)  { return indices(namedays(in)); }
9eaf1d2008-06-28Martin Nilsson  protected Calendar.TimeRanges.TimeRange _find(Calendar.TimeRanges.TimeRange t,
9f0b6c2008-02-07Martin Stjernholm  int including, int direction)
4f7b302000-09-30Mirar (Pontus Hagland)  { int jd=(int)t->julian_day(); jd+=direction*!including; [int y,int yjd,int leap]=gregorian_yjd(jd); int ld; if (y<leapdayshift) ld=55-1; // 24 feb else ld=60-1; // 29 feb if (direction==-1 && last_year!=-1 && y>last_year) [y,yjd,leap]=gregorian_year(last_year+1),jd=yjd-1; if (direction==1 && first_year!=-1 && y<first_year) [y,yjd,leap]=gregorian_year(first_year),jd=yjd; for (;;) { if (jd>=yjd+365+leap || jd<yjd) // year shift { [y,yjd,leap]=gregorian_yjd(jd); if (y<leapdayshift) ld=55-1; // 24 feb else ld=60-1; // 29 feb
f2d7a62002-02-14Martin Nilsson  if (last_year!=-1 && y>last_year) return UNDEFINED; if (first_year!=-1 && y<first_year) return UNDEFINED;
4f7b302000-09-30Mirar (Pontus Hagland)  } array(string) n; int d=jd-yjd; if (leap) { if (d<ld) n=namelist[d]; else if (d>ld) n=namelist[d-1]; else n=namelist[-1]; } else n=namelist[d]; if (n) return t->calendar()->Day("julian_r",jd,t->ruleset()); jd+=direction; } }
78fd532000-07-12Mirar (Pontus Hagland) 
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  {
4f7b302000-09-30Mirar (Pontus Hagland)  return _find(from,including,1);
78fd532000-07-12Mirar (Pontus Hagland)  }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange previous(Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  {
4f7b302000-09-30Mirar (Pontus Hagland)  return _find(from,including,-1);
78fd532000-07-12Mirar (Pontus Hagland)  } string _sprintf(int t) {
68e10f2000-09-07Mirar (Pontus Hagland)  return t=='O'?sprintf("Namedays(%s:%O)",id,name):0;
78fd532000-07-12Mirar (Pontus Hagland)  } string describe() { return "Namedays"; }
4f7b302000-09-30Mirar (Pontus Hagland)  SuperEvent|SuperNamedays|Namedays `|(SuperEvent|Namedays|SuperNamedays e, mixed ...extra) { object(SuperEvent)|object(SuperNamedays)|object(Namedays) res; if (e->is_nameday_wrapper && e->id==id && id!="?")
563bd72004-01-11Martin Nilsson  res=SuperNamedays(e->namedays|({this}),e->id);
4f7b302000-09-30Mirar (Pontus Hagland)  else {
563bd72004-01-11Martin Nilsson  array a=({e})|({this}); if (!sizeof(a)) res=this;
4f7b302000-09-30Mirar (Pontus Hagland)  else if (e->is_namedays && e->id==id) res=SuperNamedays(a,id); else res=SuperEvent(a); } if (sizeof(extra)) return predef::`|(res,@extra); return res; }
78fd532000-07-12Mirar (Pontus Hagland) }
ac8c922003-03-12Martin Nilsson //! Container for merged @[Namedays] objects.
4f7b302000-09-30Mirar (Pontus Hagland) class SuperNamedays { inherit Event; constant is_namedays_wrapper=1; // presumed non-overlapping namedays array(Nameday) namedayss; string id; void create(array(Nameday) _namedays,string _id) { name=id=_id; namedayss=_namedays; } string _sprintf(int t) { return t=='O'?sprintf("SuperNamedays(%s [%d])",id,sizeof(namedayss)):0; } string describe() { return "Namedays"; }
9f0b6c2008-02-07Martin Stjernholm  array(Calendar.TimeRanges.TimeRange) scan(Calendar.TimeRanges.TimeRange in)
4f7b302000-09-30Mirar (Pontus Hagland)  { return indices(namedays(in)); }
9f0b6c2008-02-07Martin Stjernholm  mapping(Calendar.TimeRanges.TimeRange:Event) scan_events(Calendar.TimeRanges.TimeRange in)
4f7b302000-09-30Mirar (Pontus Hagland)  { return predef::`|(@map(namedayss,"scan_events",in)); }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
4f7b302000-09-30Mirar (Pontus Hagland)  {
9f0b6c2008-02-07Martin Stjernholm  array(Calendar.TimeRanges.TimeRange) a=map(namedayss,"next", from,including)-({0});
4f7b302000-09-30Mirar (Pontus Hagland)  switch (sizeof(a)) {
f2d7a62002-02-14Martin Nilsson  case 0: return UNDEFINED;
4f7b302000-09-30Mirar (Pontus Hagland)  case 1: return a[0]; default: return min(@a); } }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange previous(Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
4f7b302000-09-30Mirar (Pontus Hagland)  {
9f0b6c2008-02-07Martin Stjernholm  array(Calendar.TimeRanges.TimeRange) a=map(namedayss,"previous",
ac8c922003-03-12Martin Nilsson  from,including)-({0});
4f7b302000-09-30Mirar (Pontus Hagland)  switch (sizeof(a)) {
f2d7a62002-02-14Martin Nilsson  case 0: return UNDEFINED;
4f7b302000-09-30Mirar (Pontus Hagland)  case 1: return a[0]; default: return max(@a); } }
9f0b6c2008-02-07Martin Stjernholm  mapping(Calendar.TimeRanges.TimeRange:array(string)) namedays(Calendar.TimeRanges.TimeRange t)
4f7b302000-09-30Mirar (Pontus Hagland)  { return predef::`|(@map(namedayss,"namedays",t)); }
9f0b6c2008-02-07Martin Stjernholm  array(string) names(Calendar.TimeRanges.TimeRange t)
4f7b302000-09-30Mirar (Pontus Hagland)  { return predef::`|(@map(namedayss,"names",t)); } SuperEvent|SuperNamedays|Namedays `|(SuperEvent|Namedays|SuperNamedays e, mixed ...extra) { if (e->is_namedays_wrapper)
563bd72004-01-11Martin Nilsson  return `|(this,@e->namedayss,@extra);
4f7b302000-09-30Mirar (Pontus Hagland)  if (e->is_namedays && e->id==id) return SuperNamedays(namedayss|({e}),id);
563bd72004-01-11Martin Nilsson  return predef::`|(e,this,@extra);
4f7b302000-09-30Mirar (Pontus Hagland)  } }
78fd532000-07-12Mirar (Pontus Hagland)  // ---------------------------------------------------------------- // simple Gregorian date events // ----------------------------------------------------------------
9eaf1d2008-06-28Martin Nilsson protected array gregorian_yjd(int jd)
78fd532000-07-12Mirar (Pontus Hagland) { int d=jd-1721426; int century=(4*d+3)/146097; int century_jd=(century*146097)/4; int century_day=d-century_jd; int century_year=(100*century_day+75)/36525; int y=century*100+century_year+1; return ({ y, 1721426+century_year*365+century_year/4+century_jd, (!(((y)%4) || (!((y)%100) && ((y)%400)))) }); }
9eaf1d2008-06-28Martin Nilsson protected array gregorian_year(int y)
78fd532000-07-12Mirar (Pontus Hagland) { return ({ y, 1721426+(y-1)*365+(y-1)/4-(y-1)/100+(y-1)/400, (!(((y)%4) || (!((y)%100) && ((y)%400)))) }); }
9eaf1d2008-06-28Martin Nilsson protected array julian_yjd(int jd)
78fd532000-07-12Mirar (Pontus Hagland) { int d=jd-1721058; int quad=d/1461; int quad_year=max( (d%1461-1)/365, 0); int y=quad*4+quad_year; return ({ y, 1721424+(y-1)*365+(y-1)/4, !(y%4), }); }
9eaf1d2008-06-28Martin Nilsson protected array julian_year(int y)
78fd532000-07-12Mirar (Pontus Hagland) { return ({ y, 1721424+(y-1)*365+(y-1)/4, !(y%4), }); }
ac8c922003-03-12Martin Nilsson //! A set date of year, counting leap day in February, //! used for the Gregorian fixed events in the events list. //! @seealso //! @[Julian_Fixed]
78fd532000-07-12Mirar (Pontus Hagland) class Gregorian_Fixed { inherit Day_Event;
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify @[Gregorian_Fixed] objects.
78fd532000-07-12Mirar (Pontus Hagland)  constant is_fixed=1; int md,mn; int yd;
5dc75a2003-03-13Martin Nilsson  //! @decl void create(string id, string name, int(1..31) month_day,@ //! int(1..12) month, int extra)
68e10f2000-09-07Mirar (Pontus Hagland)  void create(string _id,string _name, int(1..31) _md,int(1..12) _mn,int ... _n)
78fd532000-07-12Mirar (Pontus Hagland)  {
68e10f2000-09-07Mirar (Pontus Hagland)  id=_id;
78fd532000-07-12Mirar (Pontus Hagland)  name=_name; md=_md; mn=_mn; yd=M_YD[mn]+md;
45ab4c2000-08-01Mirar (Pontus Hagland)  if (sizeof(_n)) nd=_n[0];
78fd532000-07-12Mirar (Pontus Hagland)  }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { [int y,int yjd,int leap]=gregorian_yjd(jd); int njd;
45ab4c2000-08-01Mirar (Pontus Hagland)  for (;;)
78fd532000-07-12Mirar (Pontus Hagland)  {
45ab4c2000-08-01Mirar (Pontus Hagland)  if (leap && yd>59) njd=yjd+yd; else njd=yjd+yd-1; // yd start with 1 if (direction==1) { if (njd>=jd) return njd; [y,yjd,leap]=gregorian_year(y+1); } else { if (njd<=jd) return njd; [y,yjd,leap]=gregorian_year(y-1); }
78fd532000-07-12Mirar (Pontus Hagland)  } } string describe() { return sprintf("%s %2d",M_NAME[mn],md); } }
ac8c922003-03-12Martin Nilsson //! A set date of year, counting leap day in February, //! used for the Gregorian fixed events in the events list. //! @seealso //! @[Gregorian_Fixed]
78fd532000-07-12Mirar (Pontus Hagland) class Julian_Fixed { inherit Gregorian_Fixed;
ac8c922003-03-12Martin Nilsson  //! This constant may be used to identify @[Julian_Fixed] objects.
325f582000-08-06Mirar (Pontus Hagland)  constant is_julian_fixed=1;
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { [int y,int yjd,int leap]=julian_yjd(jd); int njd; for (;;) { if (leap && yd>59) njd=yjd+yd; else njd=yjd+yd-1; // yd start with 1 if (direction==1) { if (njd>=jd) return njd; [y,yjd,leap]=julian_year(y+1); } else { if (njd<=jd) return njd; [y,yjd,leap]=julian_year(y-1); } } } string describe() { return sprintf("%s %2d julian",M_NAME[mn],md); } }
ac8c922003-03-12Martin Nilsson //! This class represents the event of a given gregorian date. For instance, //! @tt{Event.Date(12,10)->next(Day())@} finds the next 12 of October.
78fd532000-07-12Mirar (Pontus Hagland) class Date { inherit Day_Event; int md,mn; int yd;
ac8c922003-03-12Martin Nilsson  //! @decl void create(int(1..31) month_day, int(1..12) month) //! The event is created by a given month day and a month number //! (1=January, 12=December).
78fd532000-07-12Mirar (Pontus Hagland)  void create(int _md,int _mn) { md=_md; mn=_mn; name=M_NAME[mn]+" "+md; yd=M_YD[mn]+md; }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { [int y,int yjd,int leap]=gregorian_yjd(jd); for (;;) { int njd; if (leap && yd>60) njd=yjd+yd; else njd=yjd+yd-1; // yd start with 1 if (((direction==1)?njd>=jd:(njd<=jd)) && njd-yjd<M_ED[leap][mn]) return njd; if (yd>M_ED[2][mn]) return NODAY; // will never happen if (direction==1) [y,yjd,leap]=gregorian_yjd(yjd+365+leap); else [y,yjd,leap]=gregorian_yjd(yjd-1); } } }
ac8c922003-03-12Martin Nilsson //! This class represents the event that a given gregorian date appears //! a given weekday. For instance, //! @tt{Event.Date_Weekday(12,10,5)->next(Day())@} finds the next 12 of //! October that is a friday.
78fd532000-07-12Mirar (Pontus Hagland) class Date_Weekday { inherit Day_Event; int md,mn; int yd; int jd_wd;
ac8c922003-03-12Martin Nilsson  //! @decl void create(int month_day, int month, int weekday) //! The event is created by a given month day, //! a month number (1=January, 12=December), and a //! weekday number (1=Monday, 7=Sunday). //! //! @note //! The week day numbers used are the same as the day of week in //! the @[ISO] calendar - the @[Gregorian] calendar has 1=Sunday, //! 7=Saturday.
78fd532000-07-12Mirar (Pontus Hagland)  void create(int _md,int _mn,int wd) { md=_md; mn=_mn; name=M_NAME[mn]+" "+md+" "+WD_NAME[wd]; yd=M_YD[mn]+md; jd_wd=(wd+6)%7; }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { if (md<1) return 0; [int y,int yjd,int leap]=gregorian_yjd(jd); for (;;) { int njd; if (leap && yd>60) njd=yjd+yd; else njd=yjd+yd-1; // yd start with 1 if (jd_wd==njd%7 && ((direction==1)?njd>=jd:(njd<=jd)) && njd-yjd<M_ED[leap][mn]) return njd; if (yd>M_ED[2][mn]) return NODAY; // will never happen if (direction==1) [y,yjd,leap]=gregorian_yjd(yjd+365+leap); else [y,yjd,leap]=gregorian_yjd(yjd-1); } } }
ac8c922003-03-12Martin Nilsson //! This class represents the event that a given gregorian //! day of month appears a given weekday. For instance,
5dc75a2003-03-13Martin Nilsson //! @tt{Event.Monthday_Weekday(13,5)->next(Day())@} finds the next
ac8c922003-03-12Martin Nilsson //! friday the 13th.
78fd532000-07-12Mirar (Pontus Hagland) class Monthday_Weekday { inherit Day_Event; int md; int jd_wd;
ac8c922003-03-12Martin Nilsson  //! @decl void create(int month_day,int weekday) //! The event is created by a given month day, //! and a weekday number (1=Monday, 7=Sunday). //! //! @note //! The week day numbers used are the same as the day of week in //! the @[ISO] calendar - the @[Gregorian] calendar has 1=Sunday, //! 7=Saturday.
78fd532000-07-12Mirar (Pontus Hagland)  void create(int _md,int wd) { md=_md; name=md+","+WD_NAME[wd]; jd_wd=(wd+6)%7; }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { if (md>31 || md<1) return 0; [int y,int yjd,int leap]=gregorian_yjd(jd); for (;;) { array z,w; if (!leap) z=({0,31,59,90,120,151,181,212,243,273,304,334}); else z=({0,31,60,91,121,152,182,213,244,274,305,335}); z=map(z,`+,yjd,md,-1); w=map(z,`%,7); if (direction==1) { foreach (enumerate(12),int i) if (w[i]==jd_wd && z[i]>=jd && z[i]-yjd<M_ED[leap][i+1]) return z[i]; [y,yjd,leap]=gregorian_yjd(yjd+365+leap); } else { foreach (enumerate(12),int i) if (w[i]==jd_wd && z[i]<=jd && z[i]-yjd<M_ED[leap][i+1]) return z[i]; [y,yjd,leap]=gregorian_yjd(yjd-1); } } } }
ac8c922003-03-12Martin Nilsson //! This class represents any given weekday. For instance, //! @tt{Event.Weekday(5)->next(Day())@} finds the next friday.
dc21d42001-05-05Mirar (Pontus Hagland) //!
ac8c922003-03-12Martin Nilsson //! These are also available as the pre-defined events @[Events.monday], //! @[Events.tuesday], @[Events.wednesday], @[Events.thursday], //! @[Events.friday], @[Events.saturday] and @[Events.sunday].
78fd532000-07-12Mirar (Pontus Hagland) class Weekday { inherit Day_Event; constant is_weekday=1; int jd_wd;
ac8c922003-03-12Martin Nilsson  //! @decl void create(int weekday, void|string id) //! The event is created by a given weekday number (1=Monday, 7=Sunday). //! //! @note //! The week day numbers used are the same as the day of week in //! the @[ISO] calendar - the @[Gregorian] calendar has 1=Sunday, //! 7=Saturday.
68e10f2000-09-07Mirar (Pontus Hagland)  void create(int wd,void|string _id)
78fd532000-07-12Mirar (Pontus Hagland)  { jd_wd=(wd+6)%7; // convert to julian day numbering name=WD_NAME[wd];
68e10f2000-09-07Mirar (Pontus Hagland)  if (!id) id=name; else id=_id;
78fd532000-07-12Mirar (Pontus Hagland)  }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { if (direction==-1) return jd-(jd-jd_wd)%7; return jd+(7-(jd-jd_wd))%7; } }
eae2282012-09-09Henrik Grubbström (Grubba) //! This class represents a solar event as observed from Earth.
48fb2f2012-09-07Henrik Grubbström (Grubba) //! //! The @[event_type] is one of //! @int //! @value 0 //! Northern hemisphere spring equinox. //! @value 1 //! Northern hemisphere summer solstice. //! @value 2
eae2282012-09-09Henrik Grubbström (Grubba) //! Northern hemisphere autumn equinox.
48fb2f2012-09-07Henrik Grubbström (Grubba) //! @value 3
eae2282012-09-09Henrik Grubbström (Grubba) //! Northern hemisphere winter solstice.
48fb2f2012-09-07Henrik Grubbström (Grubba) //! @endint class Solar(int|void event_type) { inherit Day_Event;
eae2282012-09-09Henrik Grubbström (Grubba)  //! @array //! @item //! @array //! @item 0 amplitude //! Days. //! @item 1 phase //! Radians @ year 2000. //! @item 2 period //! Radians/Year. //! @endarray //! @endarray protected constant periodic_table = ({ ({ 0.00485, 5.67162, 33.757041, }), ({ 0.00203, 5.88577, 575.338485, }), ({ 0.00199, 5.97042, 0.352312, }), ({ 0.00182, 0.48607, 7771.377155, }), ({ 0.00156, 1.27653, 786.041946, }), ({ 0.00136, 2.99359, 393.020973, }), ({ 0.00077, 3.8841, 1150.67697, }), ({ 0.00074, 5.1787, 52.96910, }), ({ 0.00070, 4.2513, 157.73436, }), ({ 0.00058, 2.0911, 588.49268, }), ({ 0.00052, 5.1866, 2.62983, }), ({ 0.00050, 0.3669, 39.81490, }), ({ 0.00045, 4.3204, 522.36940, }), ({ 0.00044, 5.6749, 550.75533, }), ({ 0.00029, 1.0634, 77.55226, }), ({ 0.00018, 2.7074, 1179.06290, }), // NB: Some have amplitude 28 here. ({ 0.00017, 5.0403, 79.62981, }), ({ 0.00016, 3.4565, 1097.70789, }), ({ 0.00014, 3.4865, 548.67778, }), ({ 0.00012, 1.6649, 254.43145, }), ({ 0.00012, 5.0110, 557.31428, }), ({ 0.00012, 5.5992, 606.97767, }), ({ 0.00009, 3.9746, 21.32991, }), ({ 0.00008, 0.2697, 294.24635, }), }); //! Calculate the next event. //! //! Based on Meeus Astronomical Algorithms Chapter 27. array(int|float) solar_event(int y)
48fb2f2012-09-07Henrik Grubbström (Grubba)  {
eae2282012-09-09Henrik Grubbström (Grubba)  int jd; float offset;
48fb2f2012-09-07Henrik Grubbström (Grubba) 
eae2282012-09-09Henrik Grubbström (Grubba)  // First calculate an initial guess for the Julian day.
48fb2f2012-09-07Henrik Grubbström (Grubba)  if (y < 1000) { float yy = y/1000.0; float y2 = yy*yy; float y3 = y2*yy; float y4 = y3*yy;
eae2282012-09-09Henrik Grubbström (Grubba)  // 4th degree polynomial around year 2BC.
48fb2f2012-09-07Henrik Grubbström (Grubba)  switch (event_type) { case 0:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365242 * yy; jd = 1721139 + (int)floor(offset); offset -= floor(offset); offset += 0.29189 + 0.13740 * yy + 0.06134 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00111 * y3 - 0.00071 * y4; break; case 1:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365241 * yy; jd = 1721233 + (int)floor(offset); offset -= floor(offset); offset += 0.25401 + 0.72562 * yy + 0.05323 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00907 * y3 - 0.00025 * y4; break; case 2:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365242 * yy; jd = 1721325 + (int)floor(offset); offset -= floor(offset); offset += 0.70455 + 0.49558 * yy + 0.11677 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00297 * y3 - 0.00074 * y4; break; case 3:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365242 * yy; jd = 1721414 + (int)floor(offset); offset -= floor(offset); offset += 0.39987 + 0.88257 * yy + 0.00769 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00933 * y3 - 0.00006 * y4; break; } } else { float yy = (y - 2000)/1000.0; float y2 = yy*yy; float y3 = y2*yy; float y4 = y3*yy;
eae2282012-09-09Henrik Grubbström (Grubba)  // 4th degree polynomial around year 2000.
48fb2f2012-09-07Henrik Grubbström (Grubba)  switch (event_type) { case 0:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365242 * yy; jd = 2451623 + (int)floor(offset); offset -= floor(offset); offset += 0.80984 + 0.37404 * yy + 0.05169 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00411 * y3 - 0.00057 * y4; break; case 1:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365241 * yy; jd = 2451716 + (int)floor(offset); offset -= floor(offset); offset += 0.56767 + 0.62603 * yy + 0.00325 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00888 * y3 - 0.00030 * y4; break; case 2:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365242 * yy; jd = 2451810 + (int)floor(offset); offset -= floor(offset); offset += 0.21715 + 0.01767 * yy + 0.11575 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00337 * y3 - 0.00078 * y4; break; case 3:
eae2282012-09-09Henrik Grubbström (Grubba)  offset = 365242 * yy; jd = 2451900 + (int)floor(offset); offset -= floor(offset); offset += 0.05952 + 0.74049 * yy + 0.06223 * y2 -
48fb2f2012-09-07Henrik Grubbström (Grubba)  0.00823 * y3 - 0.00032 * y4; break; } }
eae2282012-09-09Henrik Grubbström (Grubba)  float delta_y = ((jd - 2451545) + offset) / 36525.0; // Omega is in radians. float omega = 628.30759 * delta_y - 0.0431096; float l = 1.0 + 0.0334 * cos(omega) + 0.0007 * cos(2.0 * omega); // Adjusted to radians. float S = 0.0; foreach(periodic_table; int i; array(float) fun) { S += fun[0] * cos(fun[1] + fun[2] * delta_y); } offset += S / l; // Adjust for Meeus starting julian days at 12:00 UTC. offset += 0.5; jd += (int)floor(offset); offset -= (int)floor(offset); return ({ jd, offset });
48fb2f2012-09-07Henrik Grubbström (Grubba)  } //! @note //! Returns unixtime in UTC to avoid losing the decimals! int scan_jd(Calendar.Calendar realm, int jd, int(1..1)|int(-1..-1) direction) { [int y, int yjd, int leap] = gregorian_yjd(jd);
eae2282012-09-09Henrik Grubbström (Grubba)  [int new_jd, float offset] = solar_event(y);
48fb2f2012-09-07Henrik Grubbström (Grubba) 
eae2282012-09-09Henrik Grubbström (Grubba)  if ((direction > 0) && (new_jd < jd)) { [new_jd, offset] = solar_event(y + 1); } else if ((direction < 0) && (new_jd >= jd)) { [int new_jd, offset] = solar_event(y - 1);
48fb2f2012-09-07Henrik Grubbström (Grubba)  } // Convert into an UTC timestamp.
eae2282012-09-09Henrik Grubbström (Grubba)  return (new_jd - 2440588)*86400 + (int)(offset * 86400.0);
48fb2f2012-09-07Henrik Grubbström (Grubba)  } Calendar.TimeRanges.TimeRange next(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including) { if (!from) from=std_day(); int jd; if (including) jd=(int)(from->julian_day()); else jd=(int)(from->end()->julian_day()); int utc = scan_jd(from->calendar(),jd-nd+1,1); return (from->calendar()->Day)("unix_r",utc,from->ruleset())*nd; } //! Uses the virtual method @[scan_jd]. //! @seealso //! @[Event.previous] Calendar.TimeRanges.TimeRange previous(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including) { if (!from) from=std_day(); int jd; if (including) jd=(int)(from->end()->julian_day()); else jd=(floatp(from->julian_day()) ?(int)floor(from->julian_day()) :(from->julian_day()-1)); int utc = scan_jd(from->calendar(),jd+nd-1,-1); return (from->calendar()->Day)("unix_r",utc,from->ruleset())*nd; } }
78fd532000-07-12Mirar (Pontus Hagland) 
ac8c922003-03-12Martin Nilsson //! This class represents an easter.
78fd532000-07-12Mirar (Pontus Hagland) class Easter { inherit Day_Event; int shift=1582;
ac8c922003-03-12Martin Nilsson  //! @decl void create(void|int shift) //! @[shift] is the year to shift from old to new style easter //! calculation. Default is 1582.
78fd532000-07-12Mirar (Pontus Hagland)  void create(void|int _shift) { if (_shift) shift=_shift; }
9eaf1d2008-06-28Martin Nilsson  protected int new_style(int y)
78fd532000-07-12Mirar (Pontus Hagland)  { int century=y/100; int solar=century-century/4; int lunar=(century-15-(century-17)/25)/3; int epact=(13+11*(y%19)-solar+lunar)%30; // if (epact<0) epact+=30; // not neccesary for pike int new_moon=31-epact; // werror("epact: %O\n",epact); // werror("new_moon: %O\n",new_moon); if (new_moon<8) if (epact==24 || epact==25 && (y%19)>10) new_moon+=29; else new_moon+=30; int full_moon=new_moon+13; int week_day=(2+y+y/4-solar+full_moon)%7; return full_moon+7-week_day; }
9eaf1d2008-06-28Martin Nilsson  protected int old_style(int y)
78fd532000-07-12Mirar (Pontus Hagland)  { #if 1 int new_moon=23-11*(y%19); while (new_moon<8) new_moon+=30; int full_moon=new_moon+13; int week_day=(y+y/4+full_moon)%7; return full_moon+7-week_day; #else int g=y%19; int i=(19*g+15)%30; int j=(y+y/4+i)%7; int l=i-j; int m=3+(l+40)/44; int d=l+28-31*(m/4); // werror("y=%d m=%d d=%d l=%d\n",y,m,d,l); return l+28; #endif }
ac8c922003-03-12Martin Nilsson  //! Calculates the year day for the easter.
78fd532000-07-12Mirar (Pontus Hagland)  int easter_yd(int y,int yjd,int leap) { int z=(y<shift)?old_style(y):new_style(y); return `+(yjd,z,58,leap); }
9eaf1d2008-06-28Martin Nilsson  protected array(int) my_year(int y)
78fd532000-07-12Mirar (Pontus Hagland)  { if (y<shift) return julian_year(y); return gregorian_year(y); }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { int y,yjd,leap,ejd; // werror("scan %O %O\n",jd,direction); [y,yjd,leap]=gregorian_yjd(jd); if (y<shift) [y,yjd,leap]=julian_yjd(jd); for (;;) { ejd=easter_yd(y,yjd,leap); // werror("[%O %O %O] %O (%O)\n",y,yjd,leap,ejd,ejd-yjd+1); if (direction==1) { if (ejd>=jd) return ejd; [y,yjd,leap]=my_year(y+1); } else { if (ejd<=jd) return ejd; [y,yjd,leap]=my_year(y-1); } } } }
5dc75a2003-03-13Martin Nilsson //! This class represents an easter relative event.
78fd532000-07-12Mirar (Pontus Hagland) class Easter_Relative { inherit Easter; constant is_easter_relative=1; int offset;
ac8c922003-03-12Martin Nilsson  //! @decl void create(string id, string name, int offset)
68e10f2000-09-07Mirar (Pontus Hagland)  void create(string _id,string _name,void|int _offset)
78fd532000-07-12Mirar (Pontus Hagland)  {
68e10f2000-09-07Mirar (Pontus Hagland)  id=_id;
78fd532000-07-12Mirar (Pontus Hagland)  name=_name; offset=_offset; }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { return offset+::scan_jd(realm,jd-direction*offset,direction); } string describe() { return sprintf("%seaster %+2d, %s", shift>2000?"orthodox ":"", offset,WD_NAME[(offset-1)%7+1]); } }
5dc75a2003-03-13Martin Nilsson //! This class represents an orthodox easter relative event.
78fd532000-07-12Mirar (Pontus Hagland) class Orthodox_Easter_Relative { inherit Easter_Relative;
325f582000-08-06Mirar (Pontus Hagland)  constant is_orthodox_easter_relative=1;
78fd532000-07-12Mirar (Pontus Hagland)  int offset;
ac8c922003-03-12Martin Nilsson  //! @decl void create(string id, string name, int offset)
68e10f2000-09-07Mirar (Pontus Hagland)  void create(string _id,string _name,void|int _offset)
78fd532000-07-12Mirar (Pontus Hagland)  {
68e10f2000-09-07Mirar (Pontus Hagland)  ::create(_id,_name,_offset);
78fd532000-07-12Mirar (Pontus Hagland)  shift=9999999; } }
ac8c922003-03-12Martin Nilsson //! This class represents a monthday weekday relative event or //! n:th special weekday event, e.g. //! "fourth sunday before 24 dec" => md=24,mn=12,wd=7,n=-4
78fd532000-07-12Mirar (Pontus Hagland) class Monthday_Weekday_Relative { inherit Gregorian_Fixed; constant is_fixed=0;
325f582000-08-06Mirar (Pontus Hagland)  constant is_monthday_weekday_relative=1;
78fd532000-07-12Mirar (Pontus Hagland)  int offset; int wd; int n,inclusive;
ac8c922003-03-12Martin Nilsson  //!
68e10f2000-09-07Mirar (Pontus Hagland)  void create(string id,string name,int(1..31) md,int(1..12) mn,
78fd532000-07-12Mirar (Pontus Hagland)  int(1..7) _wd,int _n,void|int(0..1) _inclusive) {
68e10f2000-09-07Mirar (Pontus Hagland)  ::create(id,name,md,mn);
78fd532000-07-12Mirar (Pontus Hagland)  n=_n; inclusive=_inclusive; // offset is the offset to the last possible day if (n<0) offset=(n+1)*7-!inclusive; else if (n>0) offset=n*7-!!inclusive; else offset=3; wd=_wd; }
9f0b6c2008-02-07Martin Stjernholm  int scan_jd(Calendar.Calendar realm,int jd,int(-1..1) direction)
78fd532000-07-12Mirar (Pontus Hagland)  { [int y,int yjd,int leap]=gregorian_yjd(jd-offset); for (;;) { int njd; int d=yd+offset; if (leap && d>59) njd=(yjd+((d)-1)+leap-( (yjd+leap+((d)+(8-wd)-1)) % 7)); else njd=(yjd+((d)-1)-( (yjd+((d)+(8-wd)-1)) % 7)); if (direction==1) { if (njd>=jd) return njd; [y,yjd,leap]=gregorian_year(y+1); } else { if (njd<=jd) return njd; [y,yjd,leap]=gregorian_year(y-1); } } } string describe() { return sprintf("%s %2d %s %+2d %s [<=%+d]", M_NAME[mn],md,WD_NAME[wd],n, inclusive?"incl":"",offset); } }
ac8c922003-03-12Martin Nilsson //! This class holds any number of events, //! and adds the functionality of event flags.
78fd532000-07-12Mirar (Pontus Hagland) //!
ac8c922003-03-12Martin Nilsson //! @note //! Scanning (scan_events,next,etc) will drop flag information. //! Dig out what you need with @[holidays] et al first.
78fd532000-07-12Mirar (Pontus Hagland) class SuperEvent { inherit Event; constant is_superevent=1; string name="SuperEvent"; mapping(Event:multiset(string)) flags=([]); array(Event) events=({});
f2d7a62002-02-14Martin Nilsson  mapping(string:Event) id2event=UNDEFINED;
78fd532000-07-12Mirar (Pontus Hagland)  array(Event) day_events=({}); array(Namedays) namedays=({}); array(Event) other_events=({});
9eaf1d2008-06-28Martin Nilsson  protected void create(array(Event) _events,
4f7b302000-09-30Mirar (Pontus Hagland)  void|mapping(Event:multiset(string)) _flags, void|string _id)
78fd532000-07-12Mirar (Pontus Hagland)  {
68e10f2000-09-07Mirar (Pontus Hagland)  if (_id) id=_id;
78fd532000-07-12Mirar (Pontus Hagland)  if (_flags) flags=_flags; foreach (_events,Event e) if (e->is_superevent) { events|=e->events; if (flags[e] && flags[e]!=(<>)) foreach (e->events,Event e2) flags[e2]=flags[e]|(e->flags[e2]||(<>)); else flags|=e->flags; m_delete(flags,e); } else events|=({e}); foreach (events,Event e) if (e->is_day_event) day_events+=({e}); else if (e->is_namedays) namedays+=({e}); else other_events+=({e}); }
ac8c922003-03-12Martin Nilsson //! @decl SuperEvent filter_flag(string flag) //! @decl SuperEvent holidays() //! @decl SuperEvent flagdays()
dc21d42001-05-05Mirar (Pontus Hagland) //! Filter out the events that has a certain flag set. //! Holidays (flag "h") are the days that are marked //! red in the calendar (non-working days), //! Flagdays (flag "f") are the days that the flag //! should be visible in (only some countries).
78fd532000-07-12Mirar (Pontus Hagland)  SuperEvent filter_flag(string flag) { array res=({}); multiset m; foreach (events,Event e) if ((m=flags[e]) && m[flag]) res+=({e});
68e10f2000-09-07Mirar (Pontus Hagland)  return SuperEvent(res,flags&res,id+"!"+flag);
78fd532000-07-12Mirar (Pontus Hagland)  } SuperEvent holidays() { return filter_flag("h"); } SuperEvent flagdays() { return filter_flag("f"); }
9f0b6c2008-02-07Martin Stjernholm  mapping(Calendar.TimeRanges.TimeRange:Event) scan_events(Calendar.TimeRanges.TimeRange in)
78fd532000-07-12Mirar (Pontus Hagland)  { mapping res=([]); foreach (events,Event e) { mapping er=e->scan_events(in);
9f0b6c2008-02-07Martin Stjernholm  foreach ((array)er,[Calendar.TimeRanges.TimeRange t,Event e])
78fd532000-07-12Mirar (Pontus Hagland)  if (res[t]) res[t]|=e; // join else res[t]=e; } return res; }
9f0b6c2008-02-07Martin Stjernholm  array(Calendar.TimeRanges.TimeRange) scan(Calendar.TimeRanges.TimeRange in)
78fd532000-07-12Mirar (Pontus Hagland)  { return indices(scan_events(in)); }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange best=0;
78fd532000-07-12Mirar (Pontus Hagland)  foreach (events,Event e) {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange y=e->next(from,including);
78fd532000-07-12Mirar (Pontus Hagland)  if (!best || y->preceeds(best)) best=y; else if (y->starts_with(best)) best|=y; } return best; }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange previous(Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
78fd532000-07-12Mirar (Pontus Hagland)  {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange best=0;
78fd532000-07-12Mirar (Pontus Hagland)  foreach (events,Event e) {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange y=e->previous(from,including);
78fd532000-07-12Mirar (Pontus Hagland)  if (!best || best->preceeds(y)) best=y; else if (y->ends_with(best)) best|=y; } return best; }
5488532003-02-11Mirar (Pontus Hagland)  Event `|(Event|SuperEvent ... with)
78fd532000-07-12Mirar (Pontus Hagland)  { with-=({0});
68e10f2000-09-07Mirar (Pontus Hagland)  return SuperEvent(events|with,flags,"?");
78fd532000-07-12Mirar (Pontus Hagland)  }
5488532003-02-11Mirar (Pontus Hagland)  Event ``|(Event|SuperEvent with) { return `|(with); }
78fd532000-07-12Mirar (Pontus Hagland) 
5488532003-02-11Mirar (Pontus Hagland)  Event `-(Event|SuperEvent ...subtract)
78fd532000-07-12Mirar (Pontus Hagland)  { array(Event) res=events-subtract;
563bd72004-01-11Martin Nilsson  if (res==events) return this;
68e10f2000-09-07Mirar (Pontus Hagland)  return SuperEvent(res,flags&res,"?");
78fd532000-07-12Mirar (Pontus Hagland)  } array(Event) cast(string to) { if (to[..4]=="array") return events; else error("Can't cast to %O\n",to); } string _sprintf(int t) { return (t!='O')?0: (sizeof(events)>5
68e10f2000-09-07Mirar (Pontus Hagland)  ? sprintf("SuperEvent(%s:%O,%O..%O [%d])", id,events[0],events[1],events[-1],
78fd532000-07-12Mirar (Pontus Hagland)  sizeof(events))
68e10f2000-09-07Mirar (Pontus Hagland)  : sprintf("SuperEvent(%s:%s)", id,map(events,lambda(Event e) { return sprintf("%O",e); })*
78fd532000-07-12Mirar (Pontus Hagland)  ",")); }
68e10f2000-09-07Mirar (Pontus Hagland) 
fc8ead2008-11-04Martin Stjernholm  Event `-> (string s) {return `[] (s);}
68e10f2000-09-07Mirar (Pontus Hagland)  Event `[](string s) { if (!id2event) id2event=mkmapping(events->id,events); return ::`[](s) || id2event[id+"/"+s] || id2event[s] || master()->resolv("Calendar")["Events"][id+"/"+s]; } array(string) _indices() { if (!id2event) id2event=mkmapping(events->id,events); return indices(id2event); } array(Event) _values() { if (!id2event) id2event=mkmapping(events->id,events); return values(id2event); }
78fd532000-07-12Mirar (Pontus Hagland) }
ac8c922003-03-12Martin Nilsson //! Event containing information about when a timezone is changed.
0332d82000-10-26Mirar (Pontus Hagland) class TZShift_Event { inherit Event; constant is_tzshift_event=1;
9f0b6c2008-02-07Martin Stjernholm  Calendar.Rule.Timezone timezone;
0332d82000-10-26Mirar (Pontus Hagland) 
9f0b6c2008-02-07Martin Stjernholm  void create(void|Calendar.Rule.Timezone _tz)
0332d82000-10-26Mirar (Pontus Hagland)  { timezone=_tz; }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange next(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
0332d82000-10-26Mirar (Pontus Hagland)  { if (!from) from=std_second(); return scan_shift(timezone||from->timezone(), from,1,including); }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange previous(void|Calendar.TimeRanges.TimeRange from, void|int(0..1) including)
0332d82000-10-26Mirar (Pontus Hagland)  { if (!from) from=std_second(); return scan_shift(timezone||from->timezone(), from,-1,including); }
ac8c922003-03-12Martin Nilsson  //!
9eaf1d2008-06-28Martin Nilsson  protected Calendar.TimeRanges.TimeRange
9f0b6c2008-02-07Martin Stjernholm  scan_shift(Calendar.Rule.Timezone tz, Calendar.TimeRanges.TimeRange from, int direction,int including)
0332d82000-10-26Mirar (Pontus Hagland)  { if (tz->whatrule) return scan_history(tz,from,direction,including); return scan_rule(tz,from,direction,including); }
ac8c922003-03-12Martin Nilsson  //!
9eaf1d2008-06-28Martin Nilsson  protected Calendar.TimeRanges.TimeRange
9f0b6c2008-02-07Martin Stjernholm  scan_history(Calendar.Rule.Timezone tz, Calendar.TimeRanges.TimeRange from, int direction,int(0..1) including)
0332d82000-10-26Mirar (Pontus Hagland)  { int ux; if ((direction==1) ^ (!!including)) ux=(from=from->end())->unix_time(); else ux=from->unix_time(); int nextshift=-1; if (direction==1) { foreach (tz->shifts,int z) if (z>=ux) { nextshift=z; break; } } else foreach (reverse(tz->shifts),int z) if (z<=ux) { nextshift=z; break; }
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange btr=0;
0332d82000-10-26Mirar (Pontus Hagland)  if (nextshift!=-1)
fd272c2000-11-13Mirar (Pontus Hagland)  btr=from->calendar()->Second("unix_r",nextshift,from->ruleset());
0332d82000-10-26Mirar (Pontus Hagland) 
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange atr=from;
0332d82000-10-26Mirar (Pontus Hagland)  for (;;) {
9f0b6c2008-02-07Martin Stjernholm  Calendar.Rule.Timezone atz=tz->whatrule(ux);
0332d82000-10-26Mirar (Pontus Hagland)  atr=scan_rule(atz,atr,direction,including); if (!atr) break; if (direction==1) { if (atr>=from) break; } else if (atr<=from) break; } if (!btr) return atr; if (!atr) return btr; if ( (direction==1)^(btr>atr) ) return btr; else return atr; }
ac8c922003-03-12Martin Nilsson  //!
9eaf1d2008-06-28Martin Nilsson  protected Calendar.TimeRanges.TimeRange
9f0b6c2008-02-07Martin Stjernholm  scan_rule(Calendar.Rule.Timezone tz, Calendar.TimeRanges.TimeRange from, int direction,int including)
0332d82000-10-26Mirar (Pontus Hagland)  { if (!tz->jd_year_periods) return 0; // non-shifting timezone int jd; if ((direction==1) ^ (!!including)) jd=(int)(from=from->end())->julian_day(); else jd=(int)from->julian_day(); [int y,int yjd,int leap_year]=gregorian_yjd(jd); for (;;) { array(array) per=tz->jd_year_periods(yjd+1); if (sizeof(per)==1) // no shifts this year { // sanity check, are we leaving all shifts behind? if (direction==-1 && y<tz->firstyear) return 0; if (direction==1 && y>tz->lastyear) return 0; } if (direction==1) { foreach (per[1..],array shift) if (shift[0]>=jd) {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange atr=from->calendar()
fd272c2000-11-13Mirar (Pontus Hagland)  ->Second("unix_r",(shift[0]-2440588)*86400+shift[1], from->ruleset());
0332d82000-10-26Mirar (Pontus Hagland)  if (atr>=from) return atr; } } else { foreach (reverse(per[1..]),array shift) if (shift[0]<=jd) {
9f0b6c2008-02-07Martin Stjernholm  Calendar.TimeRanges.TimeRange atr=from->calendar()
fd272c2000-11-13Mirar (Pontus Hagland)  ->Second("unix_r",(shift[0]-2440588)*86400+shift[1], from->ruleset());
0332d82000-10-26Mirar (Pontus Hagland)  if (atr<=from) return atr; } } [y,yjd,leap_year]=gregorian_year(y+direction); } return 0; } }