mktime.c (1886B)
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 if (tm->tm_year < 0) 51 return 0; 52 53 day = tm->tm_mday; 54 yday = 0; 55 year = MINYEAR + tm->tm_year; 56 57 if (year > _MAXYEAR) 58 return 0; 59 60 _daysmon[FEB] = FEBDAYS(year); 61 62 /* 63 * Normalize mday so that it doesn't over/underflow month 64 * Normalize month so that it doesn't over/underflow year 65 */ 66 for (mon = tm->tm_mon; day < 1; --mon) { 67 if (mon == JAN) { 68 if (year == MINYEAR) 69 return 0; 70 year--; 71 _daysmon[FEB] = FEBDAYS(year); 72 mon = DEC+1; 73 } 74 day += _daysmon[mon-1]; 75 } 76 77 for (; day > _daysmon[mon]; ++mon) { 78 day -= _daysmon[mon]; 79 if (mon == DEC) { 80 if (year == _MAXYEAR) 81 return 0; 82 year++; 83 _daysmon[FEB] = FEBDAYS(year); 84 mon = JAN-1; 85 } 86 } 87 88 for (int i = 0; i < mon; ++i) 89 yday += _daysmon[i]; 90 91 tm->tm_mon = mon; 92 tm->tm_year = year - MINYEAR; 93 tm->tm_mday = day; 94 tm->tm_yday = yday + day - 1; 95 tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7; 96 tm->tm_isdst = 0; 97 return 1; 98 } 99 100 time_t 101 mktime(struct tm *tm) 102 { 103 if (!normalize(tm)) 104 return -1; 105 return _systime(tm); 106 }