diff --git a/lib/modules/Calendar.pmod/Event.pmod b/lib/modules/Calendar.pmod/Event.pmod
index 19423fe2bb40f24e61b7a526eee5b170126600d2..feaa295f517ced90a8cf4085a5a22065d10e5946 100644
--- a/lib/modules/Calendar.pmod/Event.pmod
+++ b/lib/modules/Calendar.pmod/Event.pmod
@@ -146,10 +146,8 @@ class Day_Event
 
   //! @decl int scan_jd(Calendar.Calendar realm, int jd,@
   //!                   int(-1..-1)|int(1..1) direction)
-  //! These methods has to be defined, and is what
-  //! really does some work. It should return the next or previos
-  //! julian day (>@i{jd@}) when the event occurs,
-  //! or the constant @[NODAY] if it doesn't.
+  //! This method has to be defined, and is what
+  //! really does some work.
   //!
   //! @param direction
   //!   @int
@@ -158,6 +156,11 @@ class Day_Event
   //!     @value -1
   //!	    Backward (previous).
   //!   @endint
+  //!
+  //! @returns
+  //!   It should return the next or previous
+  //!   julian day (>@i{jd@}) when the event occurs,
+  //!   or the constant @[NODAY] if it doesn't.
 
    int scan_jd(Calendar.Calendar realm,int jd,int(1..1)|int(-1..-1) direction);
 
@@ -855,6 +858,157 @@ class Weekday
    }
 }
 
+//! This class represents a solar event.
+//!
+//! The @[event_type] is one of
+//! @int
+//!   @value 0
+//!     Northern hemisphere spring equinox.
+//!   @value 1
+//!     Northern hemisphere summer solstice.
+//!   @value 2
+//!     Northern hemisphere spring equinox.
+//!   @value 3
+//!     Northern hemisphere summer solstice.
+//! @endint
+class Solar(int|void event_type)
+{
+  inherit Day_Event;
+
+  protected float solar_event(int y)
+  {
+    float res;
+
+    if (y < 1000) {
+      float yy = y/1000.0;
+      float y2 = yy*yy;
+      float y3 = y2*yy;
+      float y4 = y3*yy;
+
+      switch (event_type) {
+      case 0:
+	res = 1721139.29189 + 365242.13740 * yy + 0.06134 * y2 -
+	  0.00111 * y3 - 0.00071 * y4;
+	break;
+      case 1:
+	res = 1721233.25401 + 365241.72562 * yy + 0.05323 * y2 -
+	  0.00907 * y3 - 0.00025 * y4;
+	break;
+      case 2:
+	res = 1721325.70455 + 365242.49558 * yy + 0.11677 * y2 -
+	  0.00297 * y3 - 0.00074 * y4;
+	break;
+      case 3:
+	res = 1721414.39987 + 365242.88257 * yy + 0.00769 * y2 -
+	  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;
+
+      switch (event_type) {
+      case 0:
+	res = 2451623.80984 + 365242.37404 * yy + 0.05169 * y2 -
+	  0.00411 * y3 - 0.00057 * y4;
+	break;
+      case 1:
+	res = 2451716.56767 + 365241.62603 * yy + 0.00325 * y2 -
+	  0.00888 * y3 - 0.00030 * y4;
+	break;
+      case 2:
+	res = 2451810.21715 + 365242.01767 * yy + 0.11575 * y2 -
+	  0.00337 * y3 - 0.00078 * y4;
+	break;
+      case 3:
+	res = 2451900.05952 + 365242.74049 * yy + 0.06223 * y2 -
+	  0.00823 * y3 - 0.00032 * y4;
+	break;
+      }
+    }
+
+    float delta_y = (res - 2451545.0) / 36525;
+
+    float omega = 628.30759 * delta_y - 0.04311;
+    float l = 1.0 + 0.0334 * cos(omega) + cos(2.0 * omega);
+
+    float S =
+      0.00485 * cos(5.6716 + 2.3411 * delta_y) +
+      0.00203 * cos(5.8858 + 3.5686 * delta_y) +
+      0.00199 * cos(5.9704 + 0.3523 * delta_y) +
+      0.00182 * cos(0.4860 + 5.3601 * delta_y) +
+      0.00156 * cos(1.2765 + 0.6438 * delta_y) +
+      0.00136 * cos(2.9936 + 3.4635 * delta_y) +
+      0.00077 * cos(3.8841 + 0.8540 * delta_y) +
+      0.00074 * cos(5.1787 + 2.7036 * delta_y) +
+      0.00070 * cos(4.2513 + 0.6547 * delta_y) +
+      0.00058 * cos(2.0911 + 4.1564 * delta_y) +
+      0.00052 * cos(5.1866 + 2.6298 * delta_y) +
+      0.00050 * cos(0.3669 + 2.1158 * delta_y) +
+      0.00045 * cos(4.3204 + 0.8650 * delta_y) +
+      0.00044 * cos(5.6749 + 4.1182 * delta_y) +
+      0.00029 * cos(1.0634 + 2.1540 * delta_y) +
+      0.00028 * cos(2.7074 + 4.1072 * delta_y) +
+      0.00017 * cos(5.0403 + 4.2316 * delta_y) +
+      0.00016 * cos(3.4565 + 4.4336 * delta_y) +
+      0.00014 * cos(3.4865 + 2.0407 * delta_y) +
+      0.00012 * cos(1.6649 + 3.1040 * delta_y) +
+      0.00012 * cos(5.0110 + 4.3940 * delta_y) +
+      0.00012 * cos(5.5992 + 3.7919 * delta_y) +
+      0.00009 * cos(3.9746 + 2.4804 * delta_y) +
+      0.00008 * cos(0.2697 + 5.2198 * delta_y);
+
+    res += S / l;
+    return res;
+  }
+
+  //! @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);
+
+    float res = solar_event(y);
+
+    if ((direction > 0) && (res < jd)) {
+      res = solar_event(y + 1);
+    } else if ((direction < 0) && (res >= jd)) {
+      res = solar_event(y - 1);
+    }
+
+    // Convert into an UTC timestamp.
+    return (int)((res - 2440588.0)*86400);
+  }
+
+  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;
+   }
+}
 
 //! This class represents an easter.
 class Easter
diff --git a/lib/modules/Calendar.pmod/Events.pmod b/lib/modules/Calendar.pmod/Events.pmod
index 05b9d9f56c7309e3b38359efcd82b99c495fb755..94578156057e90073c2e93eaf6b92ce56862a018 100644
--- a/lib/modules/Calendar.pmod/Events.pmod
+++ b/lib/modules/Calendar.pmod/Events.pmod
@@ -141,7 +141,18 @@ Event.Event make_event(string source)
 		    n,days)>=2)
 	    return Event.Easter_Relative(id,s,n);
 	 error("Events: rule error; unknown rule format:\n%O\n",source);
-	 
+
+      case "Equinox":
+	 if (sscanf(rule, "Equinox%*[ \t]%s", string type)) {
+	    switch(String.trim_all_whites(type)) {
+	    case "Vernal":
+	       return Event.Solar(0);
+	    case "Autumnal":
+	       return Event.Solar(2);
+	    }
+	 }
+	 error("Events: rule error; unknown rule format:\n%O\n",source);
+
       case "Weekday":
 	 if (sscanf(rule,"Weekday%*[ \t]%s%*[ \t]%d days",
 		    wd,days)>=2 && (n=wd2n[wd]))