diff --git a/lib/modules/Calendar.pmod/Event.pmod b/lib/modules/Calendar.pmod/Event.pmod
index feaa295f517ced90a8cf4085a5a22065d10e5946..5437abab20b98ebdb920c4d36164e9e839424578 100644
--- a/lib/modules/Calendar.pmod/Event.pmod
+++ b/lib/modules/Calendar.pmod/Event.pmod
@@ -858,7 +858,7 @@ class Weekday
    }
 }
 
-//! This class represents a solar event.
+//! This class represents a solar event as observed from Earth.
 //!
 //! The @[event_type] is one of
 //! @int
@@ -867,39 +867,95 @@ class Weekday
 //!   @value 1
 //!     Northern hemisphere summer solstice.
 //!   @value 2
-//!     Northern hemisphere spring equinox.
+//!     Northern hemisphere autumn equinox.
 //!   @value 3
-//!     Northern hemisphere summer solstice.
+//!     Northern hemisphere winter solstice.
 //! @endint
 class Solar(int|void event_type)
 {
   inherit Day_Event;
 
-  protected float solar_event(int y)
+  //! @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)
   {
-    float res;
+    int jd;
+    float offset;
 
+    // First calculate an initial guess for the Julian day.
     if (y < 1000) {
       float yy = y/1000.0;
       float y2 = yy*yy;
       float y3 = y2*yy;
       float y4 = y3*yy;
 
+      // 4th degree polynomial around year 2BC.
       switch (event_type) {
       case 0:
-	res = 1721139.29189 + 365242.13740 * yy + 0.06134 * y2 -
+	offset = 365242 * yy;
+	jd = 1721139 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.29189 + 0.13740 * yy + 0.06134 * y2 -
 	  0.00111 * y3 - 0.00071 * y4;
 	break;
       case 1:
-	res = 1721233.25401 + 365241.72562 * yy + 0.05323 * y2 -
+	offset = 365241 * yy;
+	jd = 1721233 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.25401 + 0.72562 * yy + 0.05323 * y2 -
 	  0.00907 * y3 - 0.00025 * y4;
 	break;
       case 2:
-	res = 1721325.70455 + 365242.49558 * yy + 0.11677 * y2 -
+	offset = 365242 * yy;
+	jd = 1721325 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.70455 + 0.49558 * yy + 0.11677 * y2 -
 	  0.00297 * y3 - 0.00074 * y4;
 	break;
       case 3:
-	res = 1721414.39987 + 365242.88257 * yy + 0.00769 * y2 -
+	offset = 365242 * yy;
+	jd = 1721414 + (int)floor(offset);
+	offset -= floor(offset);
+        offset += 0.39987 + 0.88257 * yy + 0.00769 * y2 -
 	  0.00933 * y3 - 0.00006 * y4;
 	break;
       }
@@ -909,59 +965,59 @@ class Solar(int|void event_type)
       float y3 = y2*yy;
       float y4 = y3*yy;
 
+      // 4th degree polynomial around year 2000.
       switch (event_type) {
       case 0:
-	res = 2451623.80984 + 365242.37404 * yy + 0.05169 * y2 -
+	offset = 365242 * yy;
+	jd = 2451623 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.80984 + 0.37404 * yy + 0.05169 * y2 -
 	  0.00411 * y3 - 0.00057 * y4;
 	break;
       case 1:
-	res = 2451716.56767 + 365241.62603 * yy + 0.00325 * y2 -
+	offset = 365241 * yy;
+	jd = 2451716 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.56767 + 0.62603 * yy + 0.00325 * y2 -
 	  0.00888 * y3 - 0.00030 * y4;
 	break;
       case 2:
-	res = 2451810.21715 + 365242.01767 * yy + 0.11575 * y2 -
+	offset = 365242 * yy;
+	jd = 2451810 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.21715 + 0.01767 * yy + 0.11575 * y2 -
 	  0.00337 * y3 - 0.00078 * y4;
 	break;
       case 3:
-	res = 2451900.05952 + 365242.74049 * yy + 0.06223 * y2 -
+	offset = 365242 * yy;
+	jd = 2451900 + (int)floor(offset);
+	offset -= floor(offset);
+	offset += 0.05952 + 0.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;
+    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 });
   }
 
   //! @note
@@ -970,16 +1026,16 @@ class Solar(int|void event_type)
   {
     [int y, int yjd, int leap] = gregorian_yjd(jd);
 
-    float res = solar_event(y);
+    [int new_jd, float offset] = solar_event(y);
 
-    if ((direction > 0) && (res < jd)) {
-      res = solar_event(y + 1);
-    } else if ((direction < 0) && (res >= jd)) {
-      res = solar_event(y - 1);
+    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);
     }
 
     // Convert into an UTC timestamp.
-    return (int)((res - 2440588.0)*86400);
+    return (new_jd - 2440588)*86400 + (int)(offset * 86400.0);
   }
 
   Calendar.TimeRanges.TimeRange next(void|Calendar.TimeRanges.TimeRange from,