1 /* This code placed in the public domain by Mark W. Eichin */ 2 3 #include <stdio.h> 4 #include "autoconf.h" 5 6 #ifdef HAVE_SYS_TYPES_H 7 #include <sys/types.h> 8 #endif 9 #ifdef HAVE_SYS_TIME_H 10 #include <sys/time.h> 11 #ifdef TIME_WITH_SYS_TIME 12 #include <time.h> 13 #endif 14 #else 15 #include <time.h> 16 #endif 17 18 /* take a struct tm, return seconds from GMT epoch */ 19 /* like mktime, this ignores tm_wday and tm_yday. */ 20 /* unlike mktime, this does not set them... it only passes a return value. */ 21 22 static const int days_in_month[12] = { 23 0, /* jan 31 */ 24 31, /* feb 28 */ 25 59, /* mar 31 */ 26 90, /* apr 30 */ 27 120, /* may 31 */ 28 151, /* jun 30 */ 29 181, /* jul 31 */ 30 212, /* aug 31 */ 31 243, /* sep 30 */ 32 273, /* oct 31 */ 33 304, /* nov 30 */ 34 334 /* dec 31 */ 35 }; 36 37 #define hasleapday(year) (year%400?(year%100?(year%4?0:1):0):1) 38 39 time_t krb5int_gmt_mktime(struct tm *t) 40 { 41 time_t accum; 42 43 #define assert_time(cnd) if(!(cnd)) return (time_t) -1 44 45 /* 46 * For 32-bit signed time_t centered on 1/1/1970, the range is: 47 * time 0x80000000 -> Fri Dec 13 16:45:52 1901 48 * time 0x7fffffff -> Mon Jan 18 22:14:07 2038 49 * 50 * So years 1901 and 2038 are allowable, but we can't encode all 51 * dates in those years, and we're not doing overflow/underflow 52 * checking for such cases. 53 */ 54 assert_time(t->tm_year>=1); 55 assert_time(t->tm_year<=138); 56 57 assert_time(t->tm_mon>=0); 58 assert_time(t->tm_mon<=11); 59 assert_time(t->tm_mday>=1); 60 assert_time(t->tm_mday<=31); 61 assert_time(t->tm_hour>=0); 62 assert_time(t->tm_hour<=23); 63 assert_time(t->tm_min>=0); 64 assert_time(t->tm_min<=59); 65 assert_time(t->tm_sec>=0); 66 assert_time(t->tm_sec<=62); 67 68 #undef assert_time 69 70 71 accum = t->tm_year - 70; 72 accum *= 365; /* 365 days/normal year */ 73 74 /* add in leap day for all previous years */ 75 if (t->tm_year >= 70) 76 accum += (t->tm_year - 69) / 4; 77 else 78 accum -= (72 - t->tm_year) / 4; 79 /* add in leap day for this year */ 80 if(t->tm_mon >= 2) /* march or later */ 81 if(hasleapday((t->tm_year + 1900))) accum += 1; 82 83 accum += days_in_month[t->tm_mon]; 84 accum += t->tm_mday-1; /* days of month are the only 1-based field */ 85 accum *= 24; /* 24 hour/day */ 86 accum += t->tm_hour; 87 accum *= 60; /* 60 minute/hour */ 88 accum += t->tm_min; 89 accum *= 60; /* 60 seconds/minute */ 90 accum += t->tm_sec; 91 92 return accum; 93 } 94 95 #ifdef TEST_LEAP 96 int 97 main (int argc, char *argv[]) 98 { 99 int yr; 100 time_t t; 101 struct tm tm = { 102 .tm_mon = 0, .tm_mday = 1, 103 .tm_hour = 0, .tm_min = 0, .tm_sec = 0, 104 }; 105 for (yr = 60; yr <= 104; yr++) 106 { 107 printf ("1/1/%d%c -> ", 1900 + yr, hasleapday((1900+yr)) ? '*' : ' '); 108 tm.tm_year = yr; 109 t = gmt_mktime (&tm); 110 if (t == (time_t) -1) 111 printf ("-1\n"); 112 else 113 { 114 long u; 115 if (t % (24 * 60 * 60)) 116 printf ("(not integral multiple of days) "); 117 u = t / (24 * 60 * 60); 118 printf ("%3ld*365%+ld\t0x%08lx\n", 119 (long) (u / 365), (long) (u % 365), 120 (long) t); 121 } 122 } 123 t = 0x80000000, printf ("time 0x%lx -> %s", t, ctime (&t)); 124 t = 0x7fffffff, printf ("time 0x%lx -> %s", t, ctime (&t)); 125 return 0; 126 } 127 #endif 128