home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / libc / qmktime.c < prev    next >
C/C++ Source or Header  |  1991-12-10  |  2KB  |  87 lines

  1. /*
  2.  * qmktime - convert a split-out date (struct tm) back into a time_t [ANSI]
  3.  */
  4.  
  5. #include <time.h>
  6. #include <sys/types.h>
  7. #include <sys/timeb.h>
  8.  
  9. #define EPOCH 1970
  10. #define DAYS_PER_400YRS    (time_t)146097
  11. #define DAYS_PER_4YRS    (time_t)1461
  12. #define DIVBY4(n) ((n) >> 2)
  13. #define YRNUM(c, y) (DIVBY4(DAYS_PER_400YRS*(c)) + DIVBY4(DAYS_PER_4YRS*(y)))
  14. #define DAYNUM(c,y,mon,d)    (YRNUM((c), (y)) + mdays[mon] + (d))
  15. #define EPOCH_DAYNUM    DAYNUM(19, 69, 10, 1)    /* really January 1, 1970 */
  16.  
  17. static char nmdays[] = {
  18.     0, 31, 28, 31,  30, 31, 30,  31, 31, 30,  31, 30, 31
  19. };
  20. /* days since start of year. mdays[0] is March, mdays[11] is February */
  21. static short mdays[] = {
  22.     0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337
  23. };
  24.  
  25. /*
  26.  * near-ANSI qmktime suitable for use by dateconv; not necessarily as paranoid
  27.  * as ANSI requires, and it may not canonicalise the struct tm.  Ignores tm_wday
  28.  * and tm_yday.
  29.  */
  30. time_t
  31. qmktime(tp)
  32. register struct tm *tp;
  33. {
  34.     register int mon = tp->tm_mon + 1;    /* convert to 1-origin */
  35.     register int day = tp->tm_mday, year = tp->tm_year + 1900;
  36.     register time_t daynum;
  37.     register int century;
  38.     time_t nrdaynum;
  39.  
  40.     if (year < EPOCH)
  41.         return -1;        /* can't represent early date */
  42.  
  43.     /*
  44.      * validate day against days-per-month table, with leap-year
  45.      * correction
  46.      */
  47.     if (day > nmdays[mon])
  48.         if (mon != 2 || year % 4 == 0 &&
  49.             (year % 100 != 0 || year % 400 == 0) && day > 29)
  50.             return -1;    /* day too large for month */
  51.  
  52.     /* split year into century and year-of-century */
  53.     century = year / 100;
  54.     year %= 100;
  55.     /*
  56.      * We calculate the day number exactly, assuming the calendar has
  57.      * always had the current leap year rules.  (The leap year rules are
  58.      * to compensate for the fact that the Earth's revolution around the
  59.      * Sun takes 365.2425 days).  We first need to rotate months so March
  60.      * is 0, since we want the last month to have the reduced number of
  61.      * days.
  62.      */
  63.     if (mon > 2)
  64.         mon -= 3;
  65.     else {
  66.         mon += 9;
  67.         if (year == 0) {
  68.             century--;
  69.             year = 99;
  70.         } else
  71.             --year;
  72.     }
  73.     daynum = -EPOCH_DAYNUM + DAYNUM(century, year, mon, day);
  74.  
  75.     /* convert to seconds */
  76.     nrdaynum = daynum =
  77.         tp->tm_sec + (tp->tm_min +(daynum*24 + tp->tm_hour)*60)*60;
  78.  
  79.     /* daylight correction */
  80.     if (tp->tm_isdst < 0)        /* unknown; find out */
  81.         tp->tm_isdst = localtime(&nrdaynum)->tm_isdst;
  82.     if (tp->tm_isdst > 0)
  83.         daynum -= 60*60;
  84.  
  85.     return daynum < 0? -1: daynum;
  86. }
  87.