Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/util/support/gmt_mktime.c
34889 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* This code placed in the public domain by Mark W. Eichin */
3
4
#include "autoconf.h"
5
#include <stdio.h>
6
7
#ifdef HAVE_SYS_TYPES_H
8
#include <sys/types.h>
9
#endif
10
#ifdef HAVE_SYS_TIME_H
11
#include <sys/time.h>
12
#endif
13
#include <time.h>
14
15
#include "k5-gmt_mktime.h"
16
17
#if !HAVE_TIMEGM || TEST_LEAP
18
static time_t gmt_mktime(struct tm *t);
19
#endif
20
21
/*
22
* Use the nonstandard timegm() (if available) to convert broken-down
23
* UTC times into time_t values. Use our custom gmt_mktime() if
24
* timegm() is not available.
25
*
26
* We use gmtime() (or gmtime_r()) when encoding ASN.1 GeneralizedTime
27
* values. On systems where a "right" (leap-second-aware) time zone
28
* is configured, gmtime() adjusts for the presence of accumulated
29
* leap seconds in the input time_t value. POSIX requires that time_t
30
* values omit leap seconds; systems configured to include leap
31
* seconds in their time_t values are non-conforming and will have
32
* difficulties exchanging timestamp information with other systems.
33
*
34
* We use krb5int_gmt_mktime() for decoding ASN.1 GeneralizedTime
35
* values. If timegm() is not available, krb5int_gmt_mktime() won't
36
* be the inverse of gmtime() on a system that counts leap seconds. A
37
* system configured with a "right" time zone probably has timegm()
38
* available; without it, an application would have no reliable way of
39
* converting broken-down UTC times into time_t values.
40
*/
41
time_t
42
krb5int_gmt_mktime(struct tm *t)
43
{
44
#if HAVE_TIMEGM
45
return timegm(t);
46
#else
47
return gmt_mktime(t);
48
#endif
49
}
50
51
#if !HAVE_TIMEGM || TEST_LEAP
52
53
/* take a struct tm, return seconds from GMT epoch */
54
/* like mktime, this ignores tm_wday and tm_yday. */
55
/* unlike mktime, this does not set them... it only passes a return value. */
56
57
static const int days_in_month[12] = {
58
0, /* jan 31 */
59
31, /* feb 28 */
60
59, /* mar 31 */
61
90, /* apr 30 */
62
120, /* may 31 */
63
151, /* jun 30 */
64
181, /* jul 31 */
65
212, /* aug 31 */
66
243, /* sep 30 */
67
273, /* oct 31 */
68
304, /* nov 30 */
69
334 /* dec 31 */
70
};
71
72
#define hasleapday(year) (year%400?(year%100?(year%4?0:1):0):1)
73
74
static time_t
75
gmt_mktime(struct tm *t)
76
{
77
uint32_t accum;
78
79
#define assert_time(cnd) if(!(cnd)) return (time_t) -1
80
81
/*
82
* For 32-bit unsigned time values starting on 1/1/1970, the range is:
83
* time 0x00000000 -> Thu Jan 1 00:00:00 1970
84
* time 0xffffffff -> Sun Feb 7 06:28:15 2106
85
*
86
* We can't encode all dates in 2106, and we're not doing overflow checking
87
* for such cases.
88
*/
89
assert_time(t->tm_year>=70);
90
assert_time(t->tm_year<=206);
91
92
assert_time(t->tm_mon>=0);
93
assert_time(t->tm_mon<=11);
94
assert_time(t->tm_mday>=1);
95
assert_time(t->tm_mday<=31);
96
assert_time(t->tm_hour>=0);
97
assert_time(t->tm_hour<=23);
98
assert_time(t->tm_min>=0);
99
assert_time(t->tm_min<=59);
100
assert_time(t->tm_sec>=0);
101
assert_time(t->tm_sec<=62);
102
103
#undef assert_time
104
105
106
accum = t->tm_year - 70;
107
accum *= 365; /* 365 days/normal year */
108
109
/* add in leap day for all previous years */
110
if (t->tm_year >= 70)
111
accum += (t->tm_year - 69) / 4;
112
else
113
accum -= (72 - t->tm_year) / 4;
114
/* add in leap day for this year */
115
if(t->tm_mon >= 2) /* march or later */
116
if(hasleapday((t->tm_year + 1900))) accum += 1;
117
118
accum += days_in_month[t->tm_mon];
119
accum += t->tm_mday-1; /* days of month are the only 1-based field */
120
accum *= 24; /* 24 hour/day */
121
accum += t->tm_hour;
122
accum *= 60; /* 60 minute/hour */
123
accum += t->tm_min;
124
accum *= 60; /* 60 seconds/minute */
125
accum += t->tm_sec;
126
127
return accum;
128
}
129
#endif /* !HAVE_TIMEGM || TEST_LEAP */
130
131
#ifdef TEST_LEAP
132
int
133
main (int argc, char *argv[])
134
{
135
int yr;
136
time_t t;
137
struct tm tm = {
138
.tm_mon = 0, .tm_mday = 1,
139
.tm_hour = 0, .tm_min = 0, .tm_sec = 0,
140
};
141
for (yr = 60; yr <= 104; yr++)
142
{
143
printf ("1/1/%d%c -> ", 1900 + yr, hasleapday((1900+yr)) ? '*' : ' ');
144
tm.tm_year = yr;
145
t = gmt_mktime (&tm);
146
if (t == (time_t) -1)
147
printf ("-1\n");
148
else
149
{
150
long u;
151
if (t % (24 * 60 * 60))
152
printf ("(not integral multiple of days) ");
153
u = t / (24 * 60 * 60);
154
printf ("%3ld*365%+ld\t0x%08lx\n",
155
(long) (u / 365), (long) (u % 365),
156
(long) t);
157
}
158
}
159
t = 0x80000000, printf ("time 0x%lx -> %s", t, ctime (&t));
160
t = 0x7fffffff, printf ("time 0x%lx -> %s", t, ctime (&t));
161
return 0;
162
}
163
#endif
164
165