mktime.c (2466B)
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 *tm) 103 { 104 time_t t; 105 int i, year; 106 struct tm *aux; 107 108 if (!normalize(tm)) 109 return -1; 110 111 t = 0; 112 year = tm->tm_year + BASEYEAR; 113 for (i = EPOCH; i < year; ++i) 114 t += _daysyear(i) * SECDAY; 115 for (i = 0; i < tm->tm_mon; ++i) 116 t += _daysmon[i] * SECDAY; 117 118 t += tm->tm_sec; 119 t += tm->tm_min * SECMIN; 120 t += tm->tm_hour * SECHOUR; 121 t += (tm->tm_mday-1) * SECDAY; 122 aux = localtime(&t); 123 124 if (tm->tm_isdst == -1) 125 tm->tm_isdst = aux->tm_isdst; 126 127 if (tm->tm_isdst == 1) { 128 tm->tm_zone = _tzname[1]; 129 tm->tm_gmtoff = _dstzone; 130 } else { 131 tm->tm_zone = _tzname[0]; 132 tm->tm_gmtoff = _timezone; 133 } 134 t += tm->tm_gmtoff; 135 136 return t; 137 }