2N/A/* This code placed in the public domain by Mark W. Eichin */
2N/A
2N/A#include <stdio.h>
2N/A#include "autoconf.h"
2N/A
2N/A#ifdef HAVE_SYS_TYPES_H
2N/A#include <sys/types.h>
2N/A#endif
2N/A#ifdef HAVE_SYS_TIME_H
2N/A#include <sys/time.h>
2N/A#ifdef TIME_WITH_SYS_TIME
2N/A#include <time.h>
2N/A#endif
2N/A#else
2N/A#include <time.h>
2N/A#endif
2N/A
2N/A/* take a struct tm, return seconds from GMT epoch */
2N/A/* like mktime, this ignores tm_wday and tm_yday. */
2N/A/* unlike mktime, this does not set them... it only passes a return value. */
2N/A
2N/Astatic const int days_in_month[12] = {
2N/A0, /* jan 31 */
2N/A31, /* feb 28 */
2N/A59, /* mar 31 */
2N/A90, /* apr 30 */
2N/A120, /* may 31 */
2N/A151, /* jun 30 */
2N/A181, /* jul 31 */
2N/A212, /* aug 31 */
2N/A243, /* sep 30 */
2N/A273, /* oct 31 */
2N/A304, /* nov 30 */
2N/A334 /* dec 31 */
2N/A};
2N/A
2N/A#define hasleapday(year) (year%400?(year%100?(year%4?0:1):0):1)
2N/A
2N/Atime_t krb5int_gmt_mktime(struct tm *t)
2N/A{
2N/A time_t accum;
2N/A
2N/A#define assert_time(cnd) if(!(cnd)) return (time_t) -1
2N/A
2N/A /*
2N/A * For 32-bit signed time_t centered on 1/1/1970, the range is:
2N/A * time 0x80000000 -> Fri Dec 13 16:45:52 1901
2N/A * time 0x7fffffff -> Mon Jan 18 22:14:07 2038
2N/A *
2N/A * So years 1901 and 2038 are allowable, but we can't encode all
2N/A * dates in those years, and we're not doing overflow/underflow
2N/A * checking for such cases.
2N/A */
2N/A assert_time(t->tm_year>=1);
2N/A assert_time(t->tm_year<=138);
2N/A
2N/A assert_time(t->tm_mon>=0);
2N/A assert_time(t->tm_mon<=11);
2N/A assert_time(t->tm_mday>=1);
2N/A assert_time(t->tm_mday<=31);
2N/A assert_time(t->tm_hour>=0);
2N/A assert_time(t->tm_hour<=23);
2N/A assert_time(t->tm_min>=0);
2N/A assert_time(t->tm_min<=59);
2N/A assert_time(t->tm_sec>=0);
2N/A assert_time(t->tm_sec<=62);
2N/A
2N/A#undef assert_time
2N/A
2N/A
2N/A accum = t->tm_year - 70;
2N/A accum *= 365; /* 365 days/normal year */
2N/A
2N/A /* add in leap day for all previous years */
2N/A if (t->tm_year >= 70)
2N/A accum += (t->tm_year - 69) / 4;
2N/A else
2N/A accum -= (72 - t->tm_year) / 4;
2N/A /* add in leap day for this year */
2N/A if(t->tm_mon >= 2) /* march or later */
2N/A if(hasleapday((t->tm_year + 1900))) accum += 1;
2N/A
2N/A accum += days_in_month[t->tm_mon];
2N/A accum += t->tm_mday-1; /* days of month are the only 1-based field */
2N/A accum *= 24; /* 24 hour/day */
2N/A accum += t->tm_hour;
2N/A accum *= 60; /* 60 minute/hour */
2N/A accum += t->tm_min;
2N/A accum *= 60; /* 60 seconds/minute */
2N/A accum += t->tm_sec;
2N/A
2N/A return accum;
2N/A}
2N/A
2N/A#ifdef TEST_LEAP
2N/Aint
2N/Amain (int argc, char *argv[])
2N/A{
2N/A int yr;
2N/A time_t t;
2N/A struct tm tm = {
2N/A .tm_mon = 0, .tm_mday = 1,
2N/A .tm_hour = 0, .tm_min = 0, .tm_sec = 0,
2N/A };
2N/A for (yr = 60; yr <= 104; yr++)
2N/A {
2N/A printf ("1/1/%d%c -> ", 1900 + yr, hasleapday((1900+yr)) ? '*' : ' ');
2N/A tm.tm_year = yr;
2N/A t = gmt_mktime (&tm);
2N/A if (t == (time_t) -1)
2N/A printf ("-1\n");
2N/A else
2N/A {
2N/A long u;
2N/A if (t % (24 * 60 * 60))
2N/A printf ("(not integral multiple of days) ");
2N/A u = t / (24 * 60 * 60);
2N/A printf ("%3ld*365%+ld\t0x%08lx\n",
2N/A (long) (u / 365), (long) (u % 365),
2N/A (long) t);
2N/A }
2N/A }
2N/A t = 0x80000000, printf ("time 0x%lx -> %s", t, ctime (&t));
2N/A t = 0x7fffffff, printf ("time 0x%lx -> %s", t, ctime (&t));
2N/A return 0;
2N/A}
2N/A#endif