ReactOS 0.4.16-dev-981-g80eb313
mktime.cpp
Go to the documentation of this file.
1//
2// mktime.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// The mktime and mkgmtime families of functions, which convert a time value in
7// a (possibly incomplete) tm structure into a time_t value, then update all of
8// the tm structure fields with the "normalized" values.
9//
11
12
13// ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed
14#define ChkAdd(dest, src1, src2) \
15 (((src1 >= 0L) && (src2 >= 0L) && (dest < 0L)) || \
16 ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)))
17
18// ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed
19#define ChkMul(dest, src1, src2) ( src1 ? (dest / src1 != src2) : 0 )
20
21
22
23// The implementation of the _mktime and _mkgmtime functions. If 'use_local_time'
24// is true, the time is assumed to be in local time; otherwise, the time is
25// assumed to be in UTC.
26template <typename TimeType>
27static TimeType __cdecl common_mktime(
28 tm* const tb,
29 bool const use_local_time
30 ) throw()
31{
32 typedef __crt_time_time_t_traits<TimeType> time_traits;
33
34 TimeType const invalid_time = static_cast<TimeType>(-1);
35
36 _VALIDATE_RETURN(tb != nullptr, EINVAL, invalid_time)
37
38 TimeType tmptm1, tmptm2, tmptm3;
39
40 // First, make sure tm_year is reasonably close to being in range.
41 if ((tmptm1 = tb->tm_year) < _BASE_YEAR - 1 || tmptm1 > time_traits::max_year + 1)
42 return (errno = EINVAL), invalid_time;
43
44 // Adjust month value so it is in the range 0 - 11. This is because
45 // we don't know how many days are in months 12, 13, 14, etc.
46 if (tb->tm_mon < 0 || tb->tm_mon > 11)
47 {
48 // No danger of overflow because the range check above.
49 tmptm1 += (tb->tm_mon / 12);
50
51 if ((tb->tm_mon %= 12) < 0)
52 {
53 tb->tm_mon += 12;
54 --tmptm1;
55 }
56
57 // Make sure year count is still in range.
58 if (tmptm1 < _BASE_YEAR - 1 || tmptm1 > time_traits::max_year + 1)
59 return (errno = EINVAL), invalid_time;
60 }
61
62 // HERE: tmptm1 holds number of elapsed years
63
64 // Calculate days elapsed minus one, in the given year, to the given
65 // month. Check for leap year and adjust if necessary.
66 tmptm2 = _days[tb->tm_mon];
67 if (__crt_time_is_leap_year(tmptm1) && tb->tm_mon > 1)
68 ++tmptm2;
69
70 // Calculate elapsed days since base date (midnight, 1/1/70, UTC)
71 //
72 // 365 days for each elapsed year since 1970, plus one more day for
73 // each elapsed leap year. no danger of overflow because of the range
74 // check (above) on tmptm1.
75 tmptm3 = (tmptm1 - _BASE_YEAR) * 365 + __crt_time_elapsed_leap_years(tmptm1);
76
77 // Elapsed days to current month (still no possible overflow)
78 tmptm3 += tmptm2;
79
80 // Elapsed days to current date. overflow is now possible.
81 tmptm1 = tmptm3 + (tmptm2 = static_cast<TimeType>(tb->tm_mday));
82 _VALIDATE_RETURN_NOEXC(!ChkAdd(tmptm1, tmptm3, tmptm2), EINVAL, invalid_time)
83
84 // HERE: tmptm1 holds number of elapsed days
85
86 // Calculate elapsed hours since base date
87 tmptm2 = tmptm1 * 24;
88 _VALIDATE_RETURN_NOEXC(!ChkMul(tmptm2, tmptm1, 24), EINVAL, invalid_time)
89
90
91 tmptm1 = tmptm2 + (tmptm3 = static_cast<TimeType>(tb->tm_hour));
92 _VALIDATE_RETURN_NOEXC(!ChkAdd(tmptm1, tmptm2, tmptm3), EINVAL, invalid_time)
93
94
95 // HERE: tmptm1 holds number of elapsed hours
96
97 // Calculate elapsed minutes since base date
98 tmptm2 = tmptm1 * 60;
99 _VALIDATE_RETURN_NOEXC(!ChkMul(tmptm2, tmptm1, 60), EINVAL, invalid_time)
100
101
102 tmptm1 = tmptm2 + (tmptm3 = static_cast<TimeType>(tb->tm_min));
103 _VALIDATE_RETURN_NOEXC(!ChkAdd(tmptm1, tmptm2, tmptm3), EINVAL, invalid_time)
104
105
106 // HERE: tmptm1 holds number of elapsed minutes
107
108 // Calculate elapsed seconds since base date
109 tmptm2 = tmptm1 * 60L;
110 _VALIDATE_RETURN_NOEXC(!ChkMul(tmptm2, tmptm1, 60L), EINVAL, invalid_time)
111
112
113 tmptm1 = tmptm2 + (tmptm3 = static_cast<TimeType>(tb->tm_sec));
114 _VALIDATE_RETURN_NOEXC(!ChkAdd(tmptm1, tmptm2, tmptm3), EINVAL, invalid_time)
115
116
117 // HERE: tmptm1 holds number of elapsed seconds
118
119 tm tbtemp;
120 if (use_local_time)
121 {
122 // Adjust for timezone. No need to check for overflow since
123 // localtime() will check its arg value
124 __tzset();
125
126 long dstbias = 0;
127 long timezone = 0;
128 _ERRCHECK(_get_dstbias(&dstbias));
130
131 tmptm1 += timezone;
132
133 // Convert this second count back into a time block structure.
134 // If localtime returns nullptr, return an error.
135 if (time_traits::localtime_s(&tbtemp, &tmptm1) != 0)
136 return (errno = EINVAL), invalid_time;
137
138 // Now must compensate for DST. The ANSI rules are to use the passed-in
139 // tm_isdst flag if it is non-negative. Otherwise, compute if DST
140 // applies. Recall that tbtemp has the time without DST compensation,
141 // but has set tm_isdst correctly.
142 if (tb->tm_isdst > 0 || (tb->tm_isdst < 0 && tbtemp.tm_isdst > 0))
143 {
144 tmptm1 += dstbias;
145 if (time_traits::localtime_s(&tbtemp, &tmptm1) != 0)
146 return (errno = EINVAL), invalid_time;
147 }
148
149 }
150 else
151 {
152 if (time_traits::gmtime_s(&tbtemp, &tmptm1) != 0)
153 return (errno = EINVAL), invalid_time;
154 }
155
156 // HERE: tmptm1 holds number of elapsed seconds, adjusted for local time if
157 // requested
158
159 *tb = tbtemp;
160 return tmptm1;
161}
162
163
164
165// Converts a tm structure value into a time_t value. These functions also
166// update the tm structure to normalize it and populate any missing fields.
167// There are three practical uses for these functions:
168//
169// (1) To convert a broken-down time to the internal time format (time_t)
170// (2) To complete the tm value with the correct tm_wday, tm_yday, or tm_isdst
171// values given the rest of the contents of the tm.
172// (3) To pass in a time structure with "out of range" values for some fields
173// and get back a "normalized" tm structure (e.g., to pass in 1/35/1987
174// and get back 2/4/1987).
175//
176// Returns the resulting time_t value on success; returns -1 on failure.
177extern "C" __time32_t __cdecl _mktime32(tm* const tb)
178{
179 return common_mktime<__time32_t>(tb, true);
180}
181
182extern "C" __time64_t __cdecl _mktime64(tm* const tb)
183{
184 return common_mktime<__time64_t>(tb, true);
185}
186
187
188
189// Converts a UTC time stored in a tm structure into a time_t value. These
190// functions also update the tm structure to normalize it and populate any
191// missing fields. Returns the resulting time_t value on success; returns
192// -1 on failure.
194{
195 return common_mktime<__time32_t>(tb, false);
196}
197
199{
200 return common_mktime<__time64_t>(tb, false);
201}
#define EINVAL
Definition: acclib.h:90
#define __cdecl
Definition: accygwin.h:79
#define _ERRCHECK(e)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
void __cdecl __tzset()
Definition: tzset.cpp:392
#define _BASE_YEAR
bool __cdecl __crt_time_is_leap_year(TimeType const yr)
TimeType __cdecl __crt_time_elapsed_leap_years(TimeType const yr)
int const _days[]
Definition: days.cpp:14
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
static TimeType __cdecl common_mktime(tm *const tb, bool const use_local_time)
Definition: mktime.cpp:27
#define ChkMul(dest, src1, src2)
Definition: mktime.cpp:19
__time32_t __cdecl _mkgmtime32(tm *const tb)
Definition: mktime.cpp:193
#define ChkAdd(dest, src1, src2)
Definition: mktime.cpp:14
__time64_t __cdecl _mktime64(tm *const tb)
Definition: mktime.cpp:182
__time64_t __cdecl _mkgmtime64(tm *const tb)
Definition: mktime.cpp:198
__time32_t __cdecl _mktime32(tm *const tb)
Definition: mktime.cpp:177
static const WCHAR tb[]
Definition: suminfo.c:285
#define errno
Definition: errno.h:18
_CRTIMP errno_t __cdecl _get_dstbias(_Out_ long *_Daylight_savings_bias)
_CRTIMP errno_t __cdecl _get_timezone(_Out_ long *_Timezone)
long __time32_t
Definition: time.h:24
Definition: fake.h:14
Definition: time.h:68
int tm_isdst
Definition: time.h:77
__int64 __time64_t
Definition: corecrt.h:619