[comp.lang.c] Date-Routines for C/UNIX ? HELP

koerberm@nixsin.UUCP (Mathias Koerber) (08/31/89)

Hello out there, I have a little problem on my hands...

I need some routines, which give me the next day, the previous day and the
day_of_week for any date given as a string "ddmmyyyy". They also should
check if the given date is correct. I thought about converting this date into
the long value for seconds since 1 Jan 1970 GMT, but this could be a bit
tedious. So if anybody out there can give me a hint on where to obtain
routines for this or knows an rather easy trick to make UNIX do this thing
for me, I'd be very delighted.

	Should more people have interest in such things, then drop me a line and
	I will summarize all the things answered to this question.

Thx a lot for bothering


Mathias

-- 
-Mathias Koerber           |Tel:   +65 / 7473828 ext 431 |Fax: +65 / 7474331
-Nixdorf Computer Singapore|EUnet: koerber.sin@nixpbe    |nerv:  koerber.sin
-2 Kallang Sector          |uunet: uunet!linus!nixbur!koerber.sin
-Singapore 1334            |[Standard-disclaimer:All views personal...     ]

mccaugh@s.cs.uiuc.edu (09/12/89)

 I tried mailing to Mathias, but no luck...anyway, here (at least) is the
 C code for day-of-week given the date as MMDDYYYY:

#include <stdio.h>
#include <time.h>
#include <ctype.h>

 void  weekday();

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

 main (argc,argv)
  int  argc;
 char *argv[];
 {
  if(argc!=2)
    fprintf(stderr, "usage:  weekday  mmddyyyy\n");
  else weekday(argv[1]);
 }


 void weekday(date)   /* given:  date = "mmddyyyy" */
        char *date;   /* print:  day of the week   */

 {
       char *dp, month[3], day[3], year[5];
        int  mm, dd, yyyy, reg_yrs, lp_yrs,
                   i, yrs, days, days_more;
       long  secs;
 static int  reg_days[12] = {0,31,59,90,120,151,181,212,243,273,304,334},
              lp_days[12] = {0,31,60,91,121,152,182,213,244,274,305,335};
       struct tm  *tp; 

  dp = date;   /* save */
  month[0] = *dp++;   month[1] = *dp++;   month[2] = '\0';  /* get "mm" */
  mm = atoi(month);                                   /* into mm as int */
  day[0] = *dp++;   day[1] = *dp++;   day[2] = '\0';        /* get "dd" */
  dd = atoi(day);                                     /* into dd as int */
  for(i=0; i<4; i++) year[i] = *dp++;
  year[4] = '\0';      /* get "yyyy" into */
  yyyy = atoi(year);   /*  yrs as an int  */
  yrs  =  yyyy - 1970;
  lp_yrs = yrs/4;   if(yrs%4 == 3) lp_yrs++;   reg_yrs  =  yrs - lp_yrs;
  days  =  365*reg_yrs + 366*lp_yrs;     /* = #(days) until given year */
  if(yyyy%4 == 0) /* yyyy = leap-year */
    days_more = lp_days[--mm];         /* = #(days) from start of yyyy */
  else  days_more = reg_days[--mm];                  /* until month mm */
  days  +=  days_more + dd;              /* = total of days altogether */
  secs  =  86400*days;         /* = #(secs) of whole days since 1/1/70 */
  tp =  localtime(&secs);
  printf("%s falls on %s.\n", date, names[tp->tm_wday]);
  return;
 }

 e.g.: weekday 091119189 reports that the date is a Monday.

 Hope this helps!

 Scott McCaughrin
 Dept. of Computer Science
 University of Illinois
 Urbana, Illinois. USA

mccaugh@s.cs.uiuc.edu (09/12/89)

 I'm sorry if my code (in the first comment) is less than neat: I did
 test it out extensively so it at least works, but could be more efficient.
 In particular, the line assigning to variable lp_yrs should read:

          lp_yrs  =  (yyyy-1)/4 - 492;

 I tried modifying that line but it was already networked.

 Not sure what was meant by requesting 'previous day' or 'next day': were
 these requests for a new date or for the name of said day? In any event,
 just take the code I gave for day-of-week and add/subtract 86400 (= #(secs)
 per day) to value 'secs' to get a new duration in seconds, then proceed
 from there.

 The easiest part is checking date-validity, as the call to 'localtime()'
 returns info to check against the given date. Upon its return, we can
 first query if UNIX returns a date consistent with our own:

     /*  check:  dd == tp->tm_mday    */
     /*  check:  mm == tp->tm_mon     */
     /*  check:  yyyy == tp->tm_year  */

 and only then should the day-of-week be printed out.
 Again, hope this helps.

 Scott McCaughrin

cml@tove.umd.edu (Christopher Lott) (09/13/89)

In article <207600039@s.cs.uiuc.edu> mccaugh@s.cs.uiuc.edu writes:
>
> I tried mailing to Mathias, but no luck...anyway, here (at least) is the
> C code for day-of-week given the date as MMDDYYYY:
>......

I was sent this function some time ago.  The author's name appears below.
Seems to work very well, and is nice and short. 

I have not tested it extensively.  If someone can tell me more about the
below-referenced "Zeller" function, I'd appreciate it.



   >From pats@cup.portal.com Thu Jun 29 10:27:56 1989
   From: pats@cup.portal.com (Pat T Shea)
   Newsgroups: comp.sys.ibm.pc
   Subject: Re: calendar code
   Date: 29 Jun 89 00:19:58 GMT
   Organization: The Portal System (TM)
   
   'think this is what ur looking for. . . . /pats.
    
   /***********************************************************************
    *
    *          int  dmy2dow( int iDay, int iMon, int iYear ) - This is my
    *             implementation of the Zeller function.  It takes day/
    *             month/year and returns the day of the week as an int
    *             with Sunday being 0.....etc.
    *  /pats @Psi!
    *  11/05/85
    ******/
   int dmy2dow( int day, int mon, int year )
   {
      int adj_mo, adj_yr, cent, cent_yrs;
    
      adj_mo = ( mon > 2 ) ? mon - 2 : mon + 10;
      adj_yr = ( mon > 2 ) ? year    : year - 1;
      cent = adj_yr / 100;
      cent_yrs = adj_yr % 100;
      return((((( 13 * adj_mo - 1 ) / 5 ) + day + cent_yrs +
                ( cent_yrs / 4 ) + ( cent / 4 ) - 2 * cent + 77 ) % 7 ));
   }

Hope this is useful to someone.

chris...
cml@tove.umd.edu    Computer Science Dept, U. Maryland at College Park
		    4122 A.V.W.  301-454-8711	<standard disclaimers>