| Summary: | Wrong calculation of easter day in calendar program | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | elmar <elmar> | ||||
| Component: | misc | Assignee: | dwmalone | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | Unspecified | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
|
Description
elmar
2000-12-27 10:10:00 UTC
Responsible Changed From-To: freebsd-bugs->dwmalone I'll have a look at this one. I may replace the code with something from the calendar faq. The following patch to callendar(1) uses the method described in
the calendar FAQ to calculate when Easter is. This seems shorter
and is better documented than the one in ostern.c at the moment.
The patch also makes the command line parsing more robust by not
assuming that the day number and month number will be exactly two
digits long. Previously calendar would silently do the wrong thing
in this case.
I'll commit this in a few days, unless anyone objects or spots any
problems.
David.
Index: day.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/usr.bin/calendar/day.c,v
retrieving revision 1.13
diff -u -r1.13 day.c
--- day.c 1999/08/28 00:59:17 1.13
+++ day.c 2000/12/27 13:51:13
@@ -165,17 +165,13 @@
time_t Mktime (dp)
char *dp;
{
- char *date;
time_t t;
- int len;
+ int d, m, y;
struct tm tm;
- if ((date = strdup(dp)) == NULL)
- errx(1, "strdup failed in Mktime");
(void)time(&t);
tp = localtime(&t);
- len = strlen(date);
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
@@ -184,31 +180,23 @@
tm.tm_mon = tp->tm_mon;
tm.tm_year = tp->tm_year;
-
- /* day */
- *(date+2) = '\0';
- tm.tm_mday = atoi(date);
-
- /* month */
- if (len >= 4) {
- *(date+5) = '\0';
- tm.tm_mon = atoi(date+3) - 1;
- }
-
- /* Year */
- if (len >= 7) {
- tm.tm_year = atoi(date+6);
-
- /* tm_year up 1900 ... */
- if (tm.tm_year > 1900)
- tm.tm_year -= 1900;
+ switch (sscanf(dp, "%d.%d.%d", &d, &m, &y)) {
+ case 3:
+ if (y > 1900)
+ y -= 1900;
+ tm.tm_year = y;
+ /* FALLTHROUGH */
+ case 2:
+ tm.tm_mon = m - 1;
+ /* FALLTHROUGH */
+ case 1:
+ tm.tm_mday = d;
}
#ifdef DEBUG
fprintf(stderr, "Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len,
asctime(&tm));
#endif
- free(date);
return(mktime(&tm));
}
Index: ostern.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/usr.bin/calendar/ostern.c,v
retrieving revision 1.8
diff -u -r1.8 ostern.c
--- ostern.c 1999/08/28 00:59:18 1.8
+++ ostern.c 2000/12/27 13:41:24
@@ -35,46 +35,35 @@
/* return year day for Easter */
+/*
+ * This code is based on the Calendar FAQ's code for how to calculate
+ * easter is. This is the Gregorian calendar version. They refer to
+ * the Algorithm of Oudin in the "Explanatory Supplement to the
+ * Astronomical Almanac".
+ */
+
int easter (year)
int year; /* 0 ... abcd, NOT since 1900 */
{
-
- int e_a, e_b, e_c, e_d, e_e,e_f, e_g, e_h, e_i, e_k,
- e_l, e_m, e_n, e_p, e_q;
-
- /* silly, but it works */
- e_a = year % 19;
- e_b = year / 100;
- e_c = year % 100;
-
- e_d = e_b / 4;
- e_e = e_b % 4;
- e_f = (e_b + 8) / 25;
- e_g = (e_b + 1 - e_f) / 3;
- e_h = ((19 * e_a) + 15 + e_b - (e_d + e_g)) % 30;
- e_i = e_c / 4;
- e_k = e_c % 4;
- e_l = (32 + 2 * e_e + 2 * e_i - (e_h + e_k)) % 7;
- e_m = (e_a + 11 * e_h + 22 * e_l) / 451;
- e_n = (e_h + e_l + 114 - (7 * e_m)) / 31;
- e_p = (e_h + e_l + 114 - (7 * e_m)) % 31;
- e_p = e_p + 1;
-
- e_q = 31 + 28;
-
- if (e_k == 0 && e_c != 0)
- e_q += 1;
-
- if (e_n == 4)
- e_q += 31;
-
- e_q += e_p;
-
-#if DEBUG
- printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", e_a , e_b , e_c , e_d , e_e , e_f , e_g , e_h , e_i , e_k , e_l , e_m , e_n , e_p , e_q);
-#endif
-
- return (e_q);
+ int G, /* Golden number - 1 */
+ C, /* Century */
+ H, /* 23 - epact % 30 */
+ I, /* days from 21 March to Paschal full moon */
+ J, /* weekday of full moon */
+ L; /* days from 21 March to Sunday on of before full moon */
+
+ G = year % 19;
+ C = year / 100;
+ H = (C - C/4 - (8*C+13)/25 + 19*G + 15) % 30;
+ I = H - (H/28)*(1 - (H/28)*(29/(H + 1))*((21 - G)/11));
+ J = (year + year/4 + I + 2 - C + C/4) % 7;
+
+ L = I - J;
+
+ if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
+ return 31 + 29 + 21 + L + 7;
+ else
+ return 31 + 28 + 21 + L + 7;
}
/* return year day for Easter or easter depending days
State Changed From-To: open->closed Fixed in -current and RELENG_4 |