[9] | 1 | /*
|
---|
| 2 | * mktime - convert local time into calendar time
|
---|
| 3 | */
|
---|
| 4 | /* $Header: /cvsup/minix/src/lib/ansi/mktime.c,v 1.1.1.1 2005/04/21 14:56:06 beng 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 | }
|
---|