xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/gmt_mktime.c (revision 7934:6aeeafc994de)
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  
krb5int_gmt_mktime(struct tm * t)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
main(int argc,char * argv[])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