🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.unix.programmer
Article #30

Re: Day_of_the_week : how to calculate ?

#30
From: Jeff Murphy
Date: Fri, 30 Oct 1992 17:32
296 lines
8786 bytes
You can accomplish it two ways:

1. Calculate the number of seconds since Dec 31 1969 17:00:00 and 
   use ctime() to return a date string, then chop upto the first space
   character, and you will have the day name (abreviated).

2. Use an algorithm.

I wrote this routine about two weeks ago, it uses an algorithm. I dont know
if there are any ones out there that are better, I didnt bother to look..
I just need a routine to return the day name to me and I wrote one...

ok.. this is an example of how to obtain the day name:

main()
{
  char *today = "103092";
  int daynumber,m,d,y;
  daynumber = weekdaynumber(today, &m, &d, &y);
  printf("%s %s %i, 19%i\n", days[daynumber], months[m], d, y);
}

the routine "weekdaynumber" returns a day number which serves as an index into
the array days[], note that tuesday is defined as day number one, since i 
calculated from Tuesday January 1, 1901. So you just print days[daynumber]
to get the day-name. It seems to work pretty well... it accounts for
leap years, 30 day months, etc... the routine chkdate() will perform 
error checking on the inputed date (if you read it from the keyboard you
can't trust those users...) it will do a bunch of checks... so you might
want to insert a "chkdate(today)" before the "daynumber=..." above...

any questions just mail me...

jeff.
---
jcmurphy@acsu.buffalo.edu                   cit network installation & repair
opnsmurf@ubvms.cc.buffalo.edu                                          sunyab
				   

---------8<----cut here------------8<---------------

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef OK
#define OK TRUE
#endif
#ifndef ERROR
#define ERROR FALSE
#endif

#define BADDAYVAL          1
#define BADMONTHVAL        2
#define NOTLEAPYEAR        3
#define BADFEBDAY          4
#define ONLY30DUDE         5

static char *days[] = { "Tuesday", "Wednesday",
		  "Thursday", "Friday", "Saturday","Sunday", "Monday"};

static char *months[] = {"January", "February", "March", "April", 
		    "May", "June", "July", "August", "September",
		    "October", "November", "December"};

#include <strings.h>

/* returns an index into array days[] also return the month, day of the
 * month and year in m, d, and y that it strips from the strings datestr 
 * written by j murphy sunyab cit Oct 1992.
 */

weekdaynumber(datestr, m, d, y)
     char *datestr;
     int *m, *d, *y; 
{
  int comp, base, a;
  int leapyear, month, day, year;
  char *basedate = "010101";  /* referenced from tuesday january 1st, 1901 */
  
  /*
   * Next we initialize the base date. For the 20th century, we use
   * Tuesday, January 1st, 1901 as the base date. This program only
   * works one century at a time, since the year argument is given
   * as only two digits.
   */

  base = date2intV2(basedate, &month, &day, &year);

  /*
   * Now we will perform some error checking on the input.
   * the chkdate() routine will check to see if you have given 31 days
   * for a month that only has 30, if you have given the correct number of
   * days for February (and also takes into account leap years).
   * chkdate() will print an error message by passing a message to a 
   * routine called alarm(*s). Then chkdate will return a value of ERROR
   * If all is ok, a value of OK will be returned.
   */

  if( chkdate(datestr) == ERROR )
    return ERROR;
  
  /*
   * Now we compute the number of days since the base day.
   * This is simply:
   *   #ofdays = year*365 + month*31 + days + #ofleapyears - fudgefactor
   * where the fudgefactor is defined as follows:
   *     1 if the month is greater than 3
   *     2 if the month is greater than 5
   *     3 if the month is greater than 8
   *     4 if the month is greater than 10
   * This will adjust for the months in the current year that only have 30
   * days.
   */

  comp = date2intV2(datestr, &month, &day, &year);
  *m = month;
  *d = day;
  *y = year;
  
  /*
   * If the date given is less than the base date, then we must quit.
   */

  if((comp == 1) || (comp < base))
    return ERROR;

  /* 
   * Now we subtract off the base date value.
   */

  comp -= base;

  /*
   * And set up a Boolean variable indicating whether or not this is
   * a leap year.
   */

  leapyear = ( (year%4) == 0 );
  
  /* 
   * We extract the day number of the week from the total number of days
   * since basedate.
   */

  a = comp % 7;
  
  /* 
   * We do some adjustments on this according to whether this is a leap year
   * and wether it is later than February.
   */

  if(leapyear)
    a--;
  if ((month > 2) && (leapyear))
    a = (comp-4) %7;
  if ((month > 2) && (!leapyear))
    a = (comp-3) %7;
  
  return a;  
}

/* 
 * This routine is different from the one that follows it, in that it
 * accounts for leap years, and months that have only 30 days. 
 * the routine that follows assumes all years have 365 days and all months
 * have 31 days. It is used only for speed purposes. If you have two dates
 * and want to rapidly compare them, then you are better off using the
 * date2int() routine, as it will be more efficient and will not return
 * all of the extra data that this routine will.
 */

unsigned char fudge[] = {3,5,8,10}; 
extern char *MAXDATEALLOWED;
extern char *MINDATEALLOWED;

date2intV2(datestr,m1,d1,y1)
     char *datestr;
     int *m1, *d1, *y1;  
{
  char mbuf[3], dbuf[3], ybuf[3];
  int isleapyear, leapfactor, fudgefactor=0, i;  

  strncpy(mbuf, &datestr[0], 2); 
  mbuf[2] = '\0';  
  *m1 = atoi(mbuf);
  if(*m1 > 12)       /* cant have a month # greater than 12 */
       return(BADMONTHVAL);

  strncpy(dbuf, &datestr[2], 2); 
  dbuf[2] = '\0';  
  *d1 = atoi(dbuf);  
  if(*d1 > 31)       /* nor can we have a day number greater than 31 */
       return(BADDAYVAL);

  strncpy(ybuf, &datestr[4], 2); 
  ybuf[2] = '\0';  
  *y1 = atoi(ybuf);

  isleapyear = *y1 % 4;
  if( (*m1 == 2) && (*d1 > 29) )
    return(BADFEBDAY);  
  if((isleapyear != 0) && (*m1 == 2) && (*d1 > 28))
    return(NOTLEAPYEAR);
  for(i = 0; i < 4; i++)
    if( (*m1 == fudge[i]+1) && (*d1 > 30) )
      return(ONLY30DUDE);
  
  if((*m1 > 2) && (isleapyear == 0))
    leapfactor = -2;
  else
    leapfactor = -3;
  leapfactor += (int) (*y1/4);
  
  for(i = 0; i < 4; i++)
    if(*m1 > fudge[i])
      fudgefactor++;

  return ((*y1 * 365) + (*m1 * 31) + *d1 + leapfactor - fudgefactor);
}

/*
 * This routine performs various error checks on the inputed date.
 * For readability, the errors were #defined 
 */

chkdate(datestr)         
     char *datestr;
{
  int tmpi;  
  int j1,j2,j3;
  
  if( strlen(datestr) != 6 )
    {
      alarm("The date must be exactly six characters long.");
      return ERROR;
    }

  if( strsrch(datestr, ".") != 0 )
    {
      alarm("The date must not contain any decimal points.");
      return ERROR;      
    }	  

  tmpi = date2intV2(datestr, &j1, &j2, &j3);
  if(tmpi == BADDAYVAL)
    {
      alarm("What the hell day is that?!?");
      return ERROR;      
    }
  if(tmpi == BADMONTHVAL)
    {
      alarm("What the hell month is that?!?");
      return ERROR;      
    }
  if(tmpi == NOTLEAPYEAR)
    {
      alarm("That is not a leap year! Feb has only 28 days in it!!!");
      return ERROR;      
    }
  if(tmpi == BADFEBDAY)
    {
      alarm("Sorry. February just doesn't have that many days...");
      return ERROR;
    }
  if(tmpi == ONLY30DUDE)
    {
      alarm("Sorry Dude! That month only has thirty days in it!");
      return ERROR;
    }
  
  if(tmpi < date2intV2(MINDATEALLOWED, &j1, &j2, &j3))
    {
      alarm("Stop living in the past!");
      return ERROR;
    }
  else if(tmpi > date2intV2(MAXDATEALLOWED, &j1, &j2, &j3))
    {
      alarm("Boy are you ahead of the times!");
      return ERROR;
    }
  return OK;  
}

alarm(s)
     char *s;
{
  printf("%s\n", s);
}
-- 
jcmurphy@acsu.buffalo.edu                   cit network installation & repair
opnsmurf@ubvms.cc.buffalo.edu                                          sunyab
				   
Technical Details
Message-ID: <Bwy3E0.EA2@acsu.buffalo.edu>
Path: arc1-ca.pugleaf.net!sparky!uunet!charon.amdahl.com!pacbell.com!iggy.GW.Vitalink.COM!cs.widener.edu!dsinc!ub!acsu.buffalo.edu!jcmurphy
References: <1992Oct28.235119.28225@netcom.com>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!charon.amdahl.com!pacbell.com!iggy.GW.Vitalink.COM!cs.widener.edu!dsinc!ub!acsu.buffalo.edu!jcmurphy
From: jcmurphy@acsu.buffalo.edu (Jeff Murphy)
Newsgroups: comp.unix.programmer
Subject: Re: Day_of_the_week : how to calculate ?
Keywords: DOW, algorithm
Message-ID: <Bwy3E0.EA2@acsu.buffalo.edu>
Date: 30 Oct 92 17:32:24 GMT
References: <1992Oct28.235119.28225@netcom.com>
Sender: nntp@acsu.buffalo.edu
Organization: UB
Lines: 296
Nntp-Posting-Host: vodalus.acsu.buffalo.edu