mktime.c (2572B)
1 #include <limits.h> 2 #include <time.h> 3 4 #include "../libc.h" 5 6 #undef mktime 7 8 static int 9 norm(int *val, int *next, int max) 10 { 11 int v = *val, n = *next, d; 12 13 if (v < 0) { 14 d = -v / max + 1; 15 v += d * max; 16 if (n > INT_MAX - d) 17 return 0; 18 n -= d; 19 } 20 if (v >= max) { 21 d = v / max; 22 v -= d * max; 23 if (n < INT_MIN + d) 24 return 0; 25 n += d; 26 } 27 28 *val = v; 29 *next = n; 30 return 1; 31 } 32 33 static int 34 normalize(struct tm *tm) 35 { 36 int mon, day, year, yday; 37 38 /* 39 * Normalize sec so that it doesn't over/underflow min 40 * Normalize min so that it doesn't over/underflow hour 41 * Normalize hour so that it doesn't over/underflow mday 42 * Normalize month so that it doesn't over/underflow year 43 */ 44 if (!norm(&tm->tm_sec, &tm->tm_min, 60) 45 || !norm(&tm->tm_min, &tm->tm_hour, 60) 46 || !norm(&tm->tm_hour, &tm->tm_mday, 24) 47 || !norm(&tm->tm_mon, &tm->tm_year, 12)) 48 return 0; 49 50 day = tm->tm_mday; 51 yday = 0; 52 year = BASEYEAR + tm->tm_year; 53 54 _daysmon[FEB] = FEBDAYS(year); 55 56 /* 57 * Normalize mday so that it doesn't over/underflow month 58 * Normalize month so that it doesn't over/underflow year 59 */ 60 for (mon = tm->tm_mon; day < 1; --mon) { 61 if (mon == JAN) { 62 if (year == INT_MIN) 63 return 0; 64 year--; 65 _daysmon[FEB] = FEBDAYS(year); 66 mon = DEC+1; 67 } 68 day += _daysmon[mon-1]; 69 } 70 71 for (; day > _daysmon[mon]; ++mon) { 72 day -= _daysmon[mon]; 73 if (mon == DEC) { 74 if (year == INT_MAX) 75 return 0; 76 year++; 77 _daysmon[FEB] = FEBDAYS(year); 78 mon = JAN-1; 79 } 80 } 81 82 if (year < INT_MIN + BASEYEAR) 83 return 0; 84 year -= BASEYEAR; 85 86 if (year > _MAXYEAR || year < _MINYEAR) 87 return 0; 88 89 for (int i = 0; i < mon; ++i) 90 yday += _daysmon[i]; 91 92 tm->tm_mon = mon; 93 tm->tm_year = year; 94 tm->tm_mday = day; 95 tm->tm_yday = yday + day - 1; 96 tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7; 97 98 return 1; 99 } 100 101 time_t 102 mktime(struct tm *ptm) 103 { 104 time_t t; 105 long off; 106 char *name; 107 int i, year; 108 struct tm tm; 109 110 tm = *ptm; 111 if (!normalize(&tm)) 112 return -1; 113 114 t = 0; 115 i = EPOCH; 116 year = tm.tm_year + BASEYEAR; 117 if (year >= EPOCH) { 118 while (i < year) 119 t += _daysyear(i++) * SECDAY; 120 } else { 121 while (i > year) 122 t -= _daysyear(--i) * SECDAY; 123 } 124 125 for (i = 0; i < tm.tm_mon; ++i) 126 t += _daysmon[i] * SECDAY; 127 128 t += tm.tm_sec; 129 t += tm.tm_min * SECMIN; 130 t += tm.tm_hour * SECHOUR; 131 t += (tm.tm_mday-1) * SECDAY; 132 133 _tzset(); 134 if (tm.tm_isdst == 0 || tm.tm_isdst < 0 && !_isdst(&tm)) 135 off = _timezone; 136 else 137 off = _dstzone; 138 139 if (off > 0 && t > _TIME_MAX - off 140 || off < 0 && t < _TIME_MIN - off) { 141 return -1; 142 } 143 t += off; 144 *ptm = *localtime(&t); 145 146 return t; 147 }