From nobody@FreeBSD.org  Wed Dec 27 02:00:12 2000
Return-Path: <nobody@FreeBSD.org>
Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21])
	by hub.freebsd.org (Postfix) with ESMTP id 9E55F37B400
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 27 Dec 2000 02:00:11 -0800 (PST)
Received: (from nobody@localhost)
	by freefall.freebsd.org (8.11.1/8.11.1) id eBRA0Ba51395;
	Wed, 27 Dec 2000 02:00:11 -0800 (PST)
	(envelope-from nobody)
Message-Id: <200012271000.eBRA0Ba51395@freefall.freebsd.org>
Date: Wed, 27 Dec 2000 02:00:11 -0800 (PST)
From: elmar@devsoft.com
Sender: nobody@FreeBSD.org
To: freebsd-gnats-submit@FreeBSD.org
Subject: Wrong calculation of easter day in calendar program
X-Send-Pr-Version: www-1.0

>Number:         23881
>Category:       misc
>Synopsis:       Wrong calculation of easter day in calendar program
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    dwmalone
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Dec 27 02:10:00 PST 2000
>Closed-Date:    Mon Mar 5 05:05:45 PST 2001
>Last-Modified:  Mon Mar 05 05:06:20 PST 2001
>Originator:     Elmar Bartel
>Release:        4.1.1
>Organization:
/dev Software GmbH
>Environment:
FreeBSD eldev 4.1.1-STABLE FreeBSD 4.1.1-STABLE #0: Mon Oct  9 20:05:30 CEST 2000     root@eldev.devsoft.com:/usr/obj/usr/src/sys/ELDEV  i386
>Description:
In file
	 /usr/src/usr.bin/calendar/ostern.c
the calculation for the easter day is wrong due to wrong/incomplete
check for leap years.
>How-To-Repeat:
Cut and paste these two lines into your shell:

echo "Easter@Ostern 2000" | tr '@' '\009' > /tmp/cal.test
calendar  -t 22.04.2000 -f /tmp/cal.test

Calendar pretends 22.04 as easter, but its on 23.04.
>Fix:
--- /tmp/ostern.c       Wed Dec 27 10:39:02 2000
+++ /tmp/ostern.c-new   Wed Dec 27 10:40:06 2000
@@ -62,7 +62,7 @@
 
     e_q = 31 + 28;
 
-    if (e_k == 0 && e_c != 0)
+    if (e_k == 0 && (e_c != 0 || (year % 400) == 0))
        e_q += 1;
 
     if (e_n == 4)


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->dwmalone 
Responsible-Changed-By: dwmalone 
Responsible-Changed-When: Wed Dec 27 03:17:38 PST 2000 
Responsible-Changed-Why:  
I'll have a look at this one. I may replace the code with something 
from the calendar faq. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=23881 

From: David Malone <dwmalone@maths.tcd.ie>
To: elmar@devsoft.com
Cc: freebsd-gnats-submit@FreeBSD.org, wosch@FreeBSD.org,
	ache@FreeBSD.org
Subject: Re: misc/23881: Wrong calculation of easter day in calendar program
Date: Wed, 27 Dec 2000 13:59:33 +0000

 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 
State-Changed-By: dwmalone 
State-Changed-When: Mon Mar 5 05:05:45 PST 2001 
State-Changed-Why:  
Fixed in -current and RELENG_4 

http://www.freebsd.org/cgi/query-pr.cgi?pr=23881 
>Unformatted:
