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 // 10 #include <corecrt_internal_time.h> 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. 26 template <typename TimeType> 27 static 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)); 129 _ERRCHECK(_get_timezone(&timezone)); 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. 177 extern "C" __time32_t __cdecl _mktime32(tm* const tb) 178 { 179 return common_mktime<__time32_t>(tb, true); 180 } 181 182 extern "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. 193 extern "C" __time32_t __cdecl _mkgmtime32(tm* const tb) 194 { 195 return common_mktime<__time32_t>(tb, false); 196 } 197 198 extern "C" __time64_t __cdecl _mkgmtime64(tm* const tb) 199 { 200 return common_mktime<__time64_t>(tb, false); 201 } 202