Re: Hypermail and leap year

> I believe the C version of the popular Hypermail program
> (<http://www.eit.com/software/hypermail/hypermail.html>), v.1.02 has a
> bug handling some dates/times after Feb. 29, 1996.  Has anyone else
> noticed and/or fixed it?

Not before, but I have now.  The bug was in getdatestr, but I fixed
a few other things as well.  The patch is below.

 ...Roy T. Fielding
    Department of Information & Computer Science    (fielding@ics.uci.edu)
    University of California, Irvine, CA 92697-3425    fax:+1(714)824-4056
    http://www.ics.uci.edu/~fielding/
==========================================================================
*** orig/hypermail.h	Fri Sep 13 22:23:40 1996
--- hypermail.h	Fri Sep 13 20:44:16 1996
***************
*** 92,98 ****
  	char *name;
  	char *subject;
  	char *datestr;
! 	int datenum;
  	struct header *left;
  	struct header *right;
  };
--- 92,98 ----
  	char *name;
  	char *subject;
  	char *datestr;
! 	long datenum;
  	struct header *left;
  	struct header *right;
  };
***************
*** 112,119 ****
  VAR char subjname[NAMESTRLEN];
  VAR char authname[NAMESTRLEN];
  VAR char errmsg[MAXLINE];
! VAR int firstdatenum;
! VAR int lastdatenum;
  VAR int bignum;
  VAR int showprogress;
  VAR int reverse;
--- 112,119 ----
  VAR char subjname[NAMESTRLEN];
  VAR char authname[NAMESTRLEN];
  VAR char errmsg[MAXLINE];
! VAR long firstdatenum;
! VAR long lastdatenum;
  VAR int bignum;
  VAR int showprogress;
  VAR int reverse;
*** orig/date.h	Fri Sep 13 22:23:39 1996
--- date.h	Fri Sep 13 20:33:54 1996
***************
*** 8,14 ****
  void convtoshortdate();
  void splitshortdate();
  long getyearsecs();
! int convtoyearsecs();
  char *getlocaltime();
  void gettimezone();
  void getthisyear();
--- 8,14 ----
  void convtoshortdate();
  void splitshortdate();
  long getyearsecs();
! long convtoyearsecs();
  char *getlocaltime();
  void gettimezone();
  void getthisyear();
*** orig/date.c	Fri Sep 13 22:23:38 1996
--- date.c	Fri Sep 13 22:20:42 1996
***************
*** 94,122 ****
  long getyearsecs(shortdate)
       char *shortdate;
  {
!         int i, yearday, yearsecs, prevyeardays;
!         int month, day, year;
  
          splitshortdate(shortdate, &month, &day, &year);
          year += CENTURY;
  
!         for (yearday = i = 0; i < month - 1; i++) {
!                 if (i == 1 && IS_LEAP(year))
!                         yearday++;
!                 yearday += monthdays[i];
          }
-         yearday += day;
  
!         prevyeardays = 0;
!         for (i = BASEYEAR; i != year; i++) {
!                 if (IS_LEAP(i))
!                         prevyeardays++;
!                 prevyeardays += DAYSPERYEAR;
          }
  
!         yearsecs = (yearday + prevyeardays) * SECSPERDAY;
!  
!         return yearsecs;
  }
  
  /* Given a long date string, it returns the number of seconds
--- 94,118 ----
  long getyearsecs(shortdate)
       char *shortdate;
  {
!         int i, month, day, year;
!         long dayspast = 0;
  
          splitshortdate(shortdate, &month, &day, &year);
          year += CENTURY;
  
!         for (i = BASEYEAR; i < year; i++) {
!                 if (IS_LEAP(i)) dayspast++;
!                 dayspast += DAYSPERYEAR;
          }
  
!         for (i = 0; i < month - 1; i++) {
!                 dayspast += monthdays[i];
          }
+         if (month > 2 && IS_LEAP(year)) dayspast++;
  
!         dayspast += day;
! 
!         return (dayspast * SECSPERDAY);
  }
  
  /* Given a long date string, it returns the number of seconds
***************
*** 123,129 ****
  ** since BASEYEAR.
  */
  
! int convtoyearsecs(date)
       char *date;
  {
          char hourstr[3], minstr[3], secstr[3], shortdate[SHORTDATELEN];
--- 119,125 ----
  ** since BASEYEAR.
  */
  
! long convtoyearsecs(date)
       char *date;
  {
          char hourstr[3], minstr[3], secstr[3], shortdate[SHORTDATELEN];
***************
*** 141,148 ****
          minutes = atoi(minstr);
          seconds = atoi(secstr);
  
!         return (int) (yearsecs + (hours * SECSPERHOUR) +
!         (minutes * SECSPERMIN) + seconds);
  }
  
  /* Gets the local time and returns it formatted.
--- 137,144 ----
          minutes = atoi(minstr);
          seconds = atoi(secstr);
  
!         return (yearsecs + (hours * SECSPERHOUR) +
!                            (minutes * SECSPERMIN) + seconds);
  }
  
  /* Gets the local time and returns it formatted.
***************
*** 196,202 ****
          register int day, year, month, hours, minutes;
          static char date[DATESTRLEN];
  
!         for (day = 0; yearsecs > SECSPERDAY; day++)
                  yearsecs -= SECSPERDAY;
  
          for (year = BASEYEAR; day > DAYSPERYEAR; year++) {
--- 192,198 ----
          register int day, year, month, hours, minutes;
          static char date[DATESTRLEN];
  
!         for (day = 0; yearsecs >= SECSPERDAY; day++)
                  yearsecs -= SECSPERDAY;
  
          for (year = BASEYEAR; day > DAYSPERYEAR; year++) {
***************
*** 205,222 ****
                  day -= DAYSPERYEAR;
          }
  
!         if (IS_LEAP(year) && day > (monthdays[0] + monthdays[1])) {
!                 day--;
!                 yearsecs -= SECSPERDAY;
!         }
! 
!         for (month = 0; day > monthdays[month]; month++)
                  day -= monthdays[month];
  
!         for (hours = 0; yearsecs > SECSPERHOUR; hours++)
                  yearsecs -= SECSPERHOUR;
  
!         for (minutes = 0; yearsecs > SECSPERMIN; minutes++)
                  yearsecs -= SECSPERMIN;
  
  #ifdef EURODATE
--- 201,220 ----
                  day -= DAYSPERYEAR;
          }
  
!         for (month = 0; day > monthdays[month]; month++) {
!                 if (month == 1 && IS_LEAP(year)) {
!                     if (day == 29)
!                         break;
!                     else
!                         day--;
!                 }
                  day -= monthdays[month];
+         }
  
!         for (hours = 0; yearsecs >= SECSPERHOUR; hours++)
                  yearsecs -= SECSPERHOUR;
  
!         for (minutes = 0; yearsecs >= SECSPERMIN; minutes++)
                  yearsecs -= SECSPERMIN;
  
  #ifdef EURODATE
***************
*** 228,233 ****
--- 226,234 ----
          days[getnweekday(month + 1, day, year)], day, months[month],
          year, hours, minutes, yearsecs, timezonestr);
  #endif
+ 
+         if (yearsecs <= 0)
+             fprintf(stderr, "Bad yearsecs %d for %s\n", yearsecs, date);
  
  	return date;
  }
*** orig/struct.c	Fri Sep 13 22:23:41 1996
--- struct.c	Fri Sep 13 20:42:48 1996
***************
*** 372,378 ****
       char *date;
       int sorttype;
  {
!         int isbigger, yearsecs;
  
          isbigger = 0;
          if (hp == NULL) {
--- 372,379 ----
       char *date;
       int sorttype;
  {
!         int isbigger;
!         long yearsecs;
  
          isbigger = 0;
          if (hp == NULL) {
***************
*** 384,390 ****
  		if (sorttype == 2) {
  			yearsecs = convtoyearsecs(date);
  			if (!yearsecs)
! 				yearsecs = getlocaltime();
  			hp->datenum = yearsecs;
  			if (!firstdatenum || yearsecs < firstdatenum)
  				firstdatenum = yearsecs;
--- 385,391 ----
  		if (sorttype == 2) {
  			yearsecs = convtoyearsecs(date);
  			if (!yearsecs)
! 				yearsecs = (long)time();
  			hp->datenum = yearsecs;
  			if (!firstdatenum || yearsecs < firstdatenum)
  				firstdatenum = yearsecs;
***************
*** 404,410 ****
  	else if (sorttype == 2) {
  		yearsecs = convtoyearsecs(date);
  		if (!yearsecs)
! 			yearsecs = getlocaltime();
  		if (reverse)
  		        isbigger = (yearsecs < hp->datenum) ? 0 : 1;
  		else
--- 405,411 ----
  	else if (sorttype == 2) {
  		yearsecs = convtoyearsecs(date);
  		if (!yearsecs)
! 			yearsecs = (long)time();
  		if (reverse)
  		        isbigger = (yearsecs < hp->datenum) ? 0 : 1;
  		else

Received on Saturday, 14 September 1996 01:40:18 UTC