1 #include <time.h> 2 3 /* 4 * BUG: Doesn't do leap years in full glory, 5 * or calendar changes. In 2038 the sign bit 6 * will be needed in clock_t, but we say it 7 * can't be represented. 8 */ 9 static int 10 dysize(int y) 11 { 12 y += 1900; /* arg is a tm_year, number of years since 1900 */ 13 if((y%4) == 0 && ((y%100) !=0 || (y%400) == 0)) 14 return 366; 15 return 365; 16 } 17 18 static int 19 dmsize(int m, int y) 20 { 21 static char sizes[12] = 22 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 23 24 if(m == 1) 25 return (dysize(y)==366)? 29 : 28; 26 else 27 return sizes[m]; 28 } 29 30 /* Reduce *v to [0, mult), adding 1 to *next for every mult 31 * subtracted from *v, and return 1 if reduction worked (no overflow) 32 */ 33 static int 34 reduce(int *v, int *next, int mult) 35 { 36 int oldnext; 37 38 while(*v < 0){ 39 *v += mult; 40 oldnext = *next; 41 *next--; 42 if(!(*next < oldnext)) 43 return 0; 44 } 45 while(*v >= mult){ 46 *v -= mult; 47 oldnext = *next; 48 *next++; 49 if(!(*next > oldnext)) 50 return 0; 51 } 52 return 1; 53 } 54 55 static int 56 jan1(int yr) 57 { 58 int y, d; 59 60 y = yr+1900; 61 d = (4+y+(y+3)/4-(y-1701)/100+(y-1601)/400+3)%7; 62 return d; 63 } 64 65 time_t 66 mktime(struct tm *t) 67 { 68 time_t a; 69 int i, d; 70 struct tm *ptm; 71 72 if(!(reduce(&t->tm_sec, &t->tm_min, 60) && 73 reduce(&t->tm_min, &t->tm_hour, 60) && 74 reduce(&t->tm_hour, &t->tm_mday, 24) && 75 reduce(&t->tm_mon, &t->tm_year, 12))) 76 return (clock_t)-1; 77 while(t->tm_mday < 1){ 78 if(--t->tm_mon == -1){ 79 t->tm_mon = 11; 80 t->tm_year--; 81 } 82 t->tm_mday += dmsize(t->tm_mon, t->tm_year); 83 } 84 while(t->tm_mday > dmsize(t->tm_mon, t->tm_year)){ 85 t->tm_mday -= dmsize(t->tm_mon, t->tm_year); 86 if(++t->tm_mon == 12){ 87 t->tm_mon = 0; 88 t->tm_year++; 89 } 90 } 91 a = t->tm_sec + 60*t->tm_min + 3600*t->tm_hour; 92 t->tm_yday = t->tm_mday-1; 93 for(i=0; i<t->tm_mon; i++) 94 t->tm_yday += dmsize(i, t->tm_year); 95 a += t->tm_yday*86400L; 96 if(t->tm_year < 70){ 97 for(i=t->tm_year; i<70; i++) 98 if((a -= dysize(i)*86400L) < 0) 99 return (clock_t)-1; 100 }else if(t->tm_year > 70){ 101 for(i=70; i<t->tm_year; i++) 102 if((a += dysize(i)*86400L) < 0) 103 return (clock_t)-1; 104 } 105 /* 106 * Now a is number of seconds past Jan 1 1970. 107 * Convert to GMT. 108 */ 109 ptm = gmtime(&a); 110 d = ptm->tm_hour; 111 ptm = localtime(&a); 112 d -= ptm->tm_hour; 113 if(d < 0) 114 d += 24; 115 if(t->tm_isdst == 0 && ptm->tm_isdst) 116 d--; 117 if(t->tm_isdst > 0 && !ptm->tm_isdst) 118 d++; 119 a += d*3600; 120 t->tm_wday = (jan1(t->tm_year)+t->tm_yday)%7; 121 return a; 122 } 123