1: /*
   2:  * mktime - convert local time into calendar time
   3:  */
   4: /* $Header: mktime.c,v 1.5 91/04/22 13:20:54 ceriel Exp $ */
   5: 
   6: /* Michael A. Temari <temari@ix.netcom.com>   03/01/96    */
   7: /*   -  fixed bug is structure fixup code                 */
   8: 
   9: #include        <time.h>
  10: #include        <limits.h>
  11: #include        "loc_time.h"
  12: 
  13: /* The code assumes that unsigned long can be converted to time_t.
  14:  * A time_t should not be wider than unsigned long, since this would mean
  15:  * that the check for overflow at the end could fail.
  16:  */
  17: time_t
  18: mktime(register struct tm *timep)
  19: {
  20:         register long day, year;
  21:         register int tm_year;
  22:         int yday, month;
  23:         register unsigned long seconds;
  24:         int overflow;
  25:         unsigned dst;
  26: 
  27:         timep->tm_min += timep->tm_sec / 60;
  28:         timep->tm_sec %= 60;
  29:         if (timep->tm_sec < 0) {
  30:                 timep->tm_sec += 60;
  31:                 timep->tm_min--;
  32:         }
  33:         timep->tm_hour += timep->tm_min / 60;
  34:         timep->tm_min = timep->tm_min % 60;
  35:         if (timep->tm_min < 0) {
  36:                 timep->tm_min += 60;
  37:                 timep->tm_hour--;
  38:         }
  39:         day = timep->tm_hour / 24;
  40:         timep->tm_hour= timep->tm_hour % 24;
  41:         if (timep->tm_hour < 0) {
  42:                 timep->tm_hour += 24;
  43:                 day--;
  44:         }
  45:         timep->tm_year += timep->tm_mon / 12;
  46:         timep->tm_mon %= 12;
  47:         if (timep->tm_mon < 0) {
  48:                 timep->tm_mon += 12;
  49:                 timep->tm_year--;
  50:         }
  51:         day += (timep->tm_mday - 1);
  52:         while (day < 0) {
  53:                 if(--timep->tm_mon < 0) {
  54:                         timep->tm_year--;
  55:                         timep->tm_mon = 11;
  56:                 }
  57:                 day += _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon];
  58:         }
  59:         while (day >= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon]) {
  60:                 day -= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon];
  61:                 if (++(timep->tm_mon) == 12) {
  62:                         timep->tm_mon = 0;
  63:                         timep->tm_year++;
  64:                 }
  65:         }
  66:         timep->tm_mday = day + 1;
  67:         _tzset();                       /* set timezone and dst info  */
  68:         year = EPOCH_YR;
  69:         if (timep->tm_year < year - YEAR0) return (time_t)-1;
  70:         seconds = 0;
  71:         day = 0;                        /* means days since day 0 now */
  72:         overflow = 0;
  73: 
  74:         /* Assume that when day becomes negative, there will certainly
  75:          * be overflow on seconds.
  76:          * The check for overflow needs not to be done for leapyears
  77:          * divisible by 400.
  78:          * The code only works when year (1970) is not a leapyear.
  79:          */
  80: #if     EPOCH_YR != 1970
  81: #error  EPOCH_YR != 1970
  82: #endif
  83:         tm_year = timep->tm_year + YEAR0;
  84: 
  85:         if (LONG_MAX / 365 < tm_year - year) overflow++;
  86:         day = (tm_year - year) * 365;
  87:         if (LONG_MAX - day < (tm_year - year) / 4 + 1) overflow++;
  88:         day += (tm_year - year) / 4
  89:                 + ((tm_year % 4) && tm_year % 4 < year % 4);
  90:         day -= (tm_year - year) / 100
  91:                 + ((tm_year % 100) && tm_year % 100 < year % 100);
  92:         day += (tm_year - year) / 400
  93:                 + ((tm_year % 400) && tm_year % 400 < year % 400);
  94: 
  95:         yday = month = 0;
  96:         while (month < timep->tm_mon) {
  97:                 yday += _ytab[LEAPYEAR(tm_year)][month];
  98:                 month++;
  99:         }
 100:         yday += (timep->tm_mday - 1);
 101:         if (day + yday < 0) overflow++;
 102:         day += yday;
 103: 
 104:         timep->tm_yday = yday;
 105:         timep->tm_wday = (day + 4) % 7;          /* day 0 was thursday (4) */
 106: 
 107:         seconds = ((timep->tm_hour * 60L) + timep->tm_min) * 60L + timep->tm_sec;
 108: 
 109:         if ((TIME_MAX - seconds) / SECS_DAY < day) overflow++;
 110:         seconds += day * SECS_DAY;
 111: 
 112:         /* Now adjust according to timezone and daylight saving time */
 113: 
 114:         if (((_timezone > 0) && (TIME_MAX - _timezone < seconds))
 115:             || ((_timezone < 0) && (seconds < -_timezone)))
 116:                 overflow++;
 117:         seconds += _timezone;
 118: 
 119:         if (timep->tm_isdst < 0)
 120:                 dst = _dstget(timep);
 121:         else if (timep->tm_isdst)
 122:                 dst = _dst_off;
 123:         else dst = 0;
 124: 
 125:         if (dst > seconds) overflow++;   /* dst is always non-negative */
 126:         seconds -= dst;
 127: 
 128:         if (overflow) return (time_t)-1;
 129: 
 130:         if ((time_t)seconds != seconds) return (time_t)-1;
 131:         return (time_t)seconds;
 132: }