diff --git a/lib/modules/Calendar.pmod/Event.pmod b/lib/modules/Calendar.pmod/Event.pmod
index da8298b3539349fe83d5ed5008494f585e902562..027b854f672639880ace839ccc0aaf214e596db8 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 ebe58270f8f22f04703662c202036d9fd324b26a..74f953f787f21a8c78de9feca8601b89720a569f 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 86c39fa3393cadaa76e7a496643445287a3a65af..b46848d7a9963c7f9edd79a26fda6dfc13133911 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);