From 0332d8dd68c9fd5f2a0422b01e936d1a944d75e3 Mon Sep 17 00:00:00 2001 From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org> Date: Thu, 26 Oct 2000 17:23:47 +0200 Subject: [PATCH] added Events.tzshift, a mechanism to figure out when a timezone shifts Rev: lib/modules/Calendar.pmod/Event.pmod:1.10 Rev: lib/modules/Calendar.pmod/Events.pmod:1.7 Rev: lib/modules/Calendar.pmod/Timezone.pmod:1.14 --- lib/modules/Calendar.pmod/Event.pmod | 150 ++++++++++++++++++++++-- lib/modules/Calendar.pmod/Events.pmod | 6 +- lib/modules/Calendar.pmod/Timezone.pmod | 15 ++- 3 files changed, 159 insertions(+), 12 deletions(-) diff --git a/lib/modules/Calendar.pmod/Event.pmod b/lib/modules/Calendar.pmod/Event.pmod index da8298b353..027b854f67 100644 --- a/lib/modules/Calendar.pmod/Event.pmod +++ b/lib/modules/Calendar.pmod/Event.pmod @@ -10,6 +10,9 @@ constant M_ED=({({0,31,59,90,120,151,181,212,243,273,304,334,365}), constant M_NAME="---JanFebMarAprMayJunJulAugSepOctNovDec"/3; constant WD_NAME="---MonTueWedThuFriSatSun"/3; +function(mixed...:TimeRange) std_day=master()->resolv("Calendar")["Day"]; +function(mixed...:TimeRange) std_second=master()->resolv("Calendar")["Second"]; + // ---------------------------------------------------------------- // base classes // ---------------------------------------------------------------- @@ -53,8 +56,8 @@ class Event constant is_event=1; - TimeRange next(TimeRange from,void|int(0..1) including); - TimeRange previous(TimeRange from,void|int(0..1) including); + TimeRange next(void|TimeRange from,void|int(0..1) including); + TimeRange previous(void|TimeRange from,void|int(0..1) including); // what events in this period? array(TimeRange) scan(TimeRange in) @@ -115,12 +118,12 @@ class NullEvent name=s; } - TimeRange next(TimeRange from,void|int(0..1) including) + TimeRange next(void|TimeRange from,void|int(0..1) including) { return 0; } - TimeRange previous(TimeRange from,void|int(0..1) including) + TimeRange previous(void|TimeRange from,void|int(0..1) including) { return 0; } @@ -162,8 +165,9 @@ class Day_Event int scan_jd(Calendar realm,int jd,int(1..1)|int(-1..-1) direction); // find - TimeRange next(TimeRange from,void|int(0..1) including) + TimeRange next(void|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()); @@ -171,8 +175,9 @@ class Day_Event return (from->calendar()->Day)("julian_r",jd,from->ruleset())*nd; } - TimeRange previous(TimeRange from,void|int(0..1) including) + TimeRange previous(void|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()) @@ -762,7 +767,7 @@ class Date_Weekday //! This class represents the event that a given gregorian //! day of month appears a given weekday. //! For instance, -//! <tt>Event.Date_Weekday(13,5)->next(Day())</tt> +//! <tt>Event.Monthday_Weekday(13,5)->next(Day())</tt> //! finds the next friday the 13th. //! //! method void create(int month_day,int weekday) @@ -1255,3 +1260,134 @@ class SuperEvent } } +class TZShift_Event +{ + inherit Event; + + constant is_tzshift_event=1; + + Ruleset.Timezone timezone; + + void create(void|Ruleset.Timezone _tz) + { + timezone=_tz; + } + + TimeRange next(void|TimeRange from,void|int(0..1) including) + { + if (!from) from=std_second(); + return scan_shift(timezone||from->timezone(), + from,1,including); + } + TimeRange previous(void|TimeRange from,void|int(0..1) including) + { + if (!from) from=std_second(); + return scan_shift(timezone||from->timezone(), + from,-1,including); + } + + static TimeRange scan_shift(Ruleset.Timezone tz, + TimeRange from, + int direction,int including) + { + if (tz->whatrule) + return scan_history(tz,from,direction,including); + return scan_rule(tz,from,direction,including); + } + + static TimeRange scan_history(Ruleset.Timezone tz, + TimeRange from, + int direction,int(0..1) including) + { + 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; } + + TimeRange btr=0; + if (nextshift!=-1) + btr=from->calendar()->Second("unix",nextshift); + + TimeRange atr=from; + for (;;) + { + Ruleset.Timezone atz=tz->whatrule(ux); + 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; + } + + static TimeRange scan_rule(Ruleset.Timezone tz, + TimeRange from, + int direction,int including) + { + 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) + { + TimeRange atr=from->calendar() + ->Second("unix",(shift[0]-2440588)*86400+shift[1]); + if (atr>=from) return atr; + } + } + else + { + foreach (reverse(per[1..]),array shift) + if (shift[0]<=jd) + { + TimeRange atr=from->calendar() + ->Second("unix",(shift[0]-2440588)*86400+shift[1]); + if (atr<=from) return atr; + } + } + [y,yjd,leap_year]=gregorian_year(y+direction); + } + + return 0; + } +} diff --git a/lib/modules/Calendar.pmod/Events.pmod b/lib/modules/Calendar.pmod/Events.pmod index ebe58270f8..74f953f787 100644 --- a/lib/modules/Calendar.pmod/Events.pmod +++ b/lib/modules/Calendar.pmod/Events.pmod @@ -361,7 +361,7 @@ function `-> = `[]; // Don't load Geogrphy.Countries unless we have to object country_lookup=0; -Event|Event.Namedays magic_event(string s) +Event.Event|Event.Namedays magic_event(string s) { Event.Event e; if ( (e=loaded_events[s]) ) return e; @@ -375,7 +375,9 @@ Event|Event.Namedays magic_event(string s) country_lookup=master()->resolv("Geography.Countries"); object c=country_lookup->from_name(s); if (c && (e=find_region(lower_case(c->iso2)))) return e; - + + if (s=="tzshift") + return loaded_events->tzshift=Event.TZShift_Event(); return ([])[0]; } diff --git a/lib/modules/Calendar.pmod/Timezone.pmod b/lib/modules/Calendar.pmod/Timezone.pmod index 86c39fa339..b46848d7a9 100644 --- a/lib/modules/Calendar.pmod/Timezone.pmod +++ b/lib/modules/Calendar.pmod/Timezone.pmod @@ -642,6 +642,7 @@ class Runtime_timezone_compiler array sr=({}); int mn=min(@indices(rules-(<NUL_YEAR>))); + int firstyear=99999,lastyear=0; for (y=INF_YEAR;sizeof(r2);y--) if (r2[y]) @@ -659,6 +660,8 @@ class Runtime_timezone_compiler int y0=min(@(array)my); int y2=max(@(array)my); + if (y0!=NUL_YEAR && y0<firstyear) firstyear=y0; + if (y2!=INF_YEAR && y2>lastyear) lastyear=y2; for (; y0<=y2; y0++) if (my[y0]) { @@ -666,9 +669,11 @@ class Runtime_timezone_compiler while (my[++y1]); y1--; - + + // figure first and last interesting year if (y0==NUL_YEAR) { + if (y1!=NUL_YEAR && y1<firstyear) firstyear=y1; if (my[INF_YEAR]) tr+=({" default: // .."+max(y1,mn-1), " and ½½½..\n"}); @@ -678,8 +683,10 @@ class Runtime_timezone_compiler } else if (y0==y1) tr+=({" case "+y0+":\n"}); - else if (y1==2050) + else if (y1==INF_YEAR) { + if (y0>lastyear) lastyear=y0; + if (!my[NUL_YEAR]) tr+=({" case "+y0,"..:\n"}); else @@ -705,6 +712,8 @@ class Runtime_timezone_compiler ({" }\n" " }\n" "\n" + "constant firstyear="+firstyear+";\n" + "constant lastyear="+lastyear+";\n", "array(string) rule_s=\n"}); multiset tzname=(<>); @@ -1133,7 +1142,7 @@ class Runtime_timezone_compiler if (sscanf(line,"Rule%*[ \t]%[^ \t]%*[ \t]%s",a,b)==4 && a==s) r->add(b); - else + else if (sscanf(line,"%*[ ]#%*s")<2) break; // end of zone #ifdef RTTZC_TIMING float tf=time(t); -- GitLab