Reactos
at listview 211 lines 6.9 kB view raw
1// 2// localtime.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines the localtime family of functions, which convert a time_t to a tm 7// structure containing the local time. 8// 9#include <corecrt_internal_time.h> 10 11 12 13// Converts a time_t value to a tm value containing the corresponding local time. 14// Returns zero and updates the tm structure on success; returns nonzero and 15// leaves the tm structure in an indeterminate state on failure. 16// 17// Assumptions: 18// (1) gmtime must be called before _isindst to ensure that the tb time 19// structure is initialized. 20// (2) gmtime, _gtime64, localtime and _localtime64() all use a single 21// statically allocated buffer. Each call to one of these routines 22// destroys the contents of the previous call. 23// (3) It is assumed that __time64_t is a 64-bit integer representing 24// the number of seconds since 00:00:00, 01-01-70 (UTC) (i.e., the 25// Posix/Unix Epoch. Only non-negative values are supported. 26// (4) It is assumed that the maximum adjustment for local time is 27// less than three days (include Daylight Savings Time adjustment). 28// This only a concern in Posix where the specification of the TZ 29// environment restricts the combined offset for time zone and 30// Daylight Savings Time to 2 * (24:59:59), just under 50 hours. 31// If any of these assumptions are violated, the behavior is undefined. 32template <typename TimeType> 33static errno_t __cdecl common_localtime_s( 34 tm* const ptm, 35 TimeType const* const ptime 36 ) throw() 37{ 38 typedef __crt_time_time_t_traits<TimeType> time_traits; 39 40 _VALIDATE_RETURN_ERRCODE(ptm != nullptr, EINVAL); 41 memset(ptm, 0xff, sizeof(tm)); 42 43 _VALIDATE_RETURN_ERRCODE(ptime != nullptr, EINVAL); 44 45 // Check for illegal time_t value: 46 _VALIDATE_RETURN_ERRCODE_NOEXC(*ptime >= 0, EINVAL); 47 _VALIDATE_RETURN_ERRCODE_NOEXC(*ptime <= time_traits::max_time_t, EINVAL); 48 49 __tzset(); 50 51 int daylight = 0; 52 long dstbias = 0; 53 long timezone = 0; 54 _ERRCHECK(_get_daylight(&daylight)); 55 _ERRCHECK(_get_dstbias (&dstbias )); 56 _ERRCHECK(_get_timezone(&timezone)); 57 58 if (*ptime > 3 * _DAY_SEC && *ptime < time_traits::max_time_t - 3 * _DAY_SEC) 59 { 60 // The date does not fall within the first three or last three representable 61 // days; therefore, there is no possibility of overflowing or underflowing 62 // the time_t representation as we compensate for time zone and daylight 63 // savings time. 64 TimeType ltime = *ptime - timezone; 65 66 errno_t status0 = time_traits::gmtime_s(ptm, &ltime); 67 if (status0 != 0) 68 return status0; 69 70 // Check and adjust for daylight savings time: 71 if (daylight && _isindst(ptm)) 72 { 73 ltime -= dstbias; 74 75 errno_t const status1 = time_traits::gmtime_s(ptm, &ltime); 76 if (status1 != 0) 77 return status1; 78 79 ptm->tm_isdst = 1; 80 } 81 } 82 else 83 { 84 // The date falls within the first three or last three representable days; 85 // therefore, it is possible that the time_t representation would overflow 86 // or underflow while compensating for time zone and daylight savings time. 87 // Therefore, we make the time zone and daylight savings time adjustments 88 // directly in the tm structure. 89 errno_t const status0 = time_traits::gmtime_s(ptm, ptime); 90 if (status0 != 0) 91 return status0; 92 93 TimeType ltime = static_cast<TimeType>(ptm->tm_sec); 94 95 // First, adjust for the time zone: 96 if (daylight && _isindst(ptm)) 97 { 98 ltime -= (timezone + dstbias); 99 ptm->tm_isdst = 1; 100 } 101 else 102 { 103 ltime -= timezone; 104 } 105 106 ptm->tm_sec = static_cast<int>(ltime % 60); 107 if (ptm->tm_sec < 0) 108 { 109 ptm->tm_sec += 60; 110 ltime -= 60; 111 } 112 113 ltime = static_cast<TimeType>(ptm->tm_min) + ltime / 60; 114 ptm->tm_min = static_cast<int>(ltime % 60); 115 if (ptm->tm_min < 0) 116 { 117 ptm->tm_min += 60; 118 ltime -= 60; 119 } 120 121 ltime = static_cast<TimeType>(ptm->tm_hour) + ltime / 60; 122 ptm->tm_hour = static_cast<int>(ltime % 24); 123 if (ptm->tm_hour < 0) 124 { 125 ptm->tm_hour += 24; 126 ltime -=24; 127 } 128 129 ltime /= 24; 130 131 if (ltime > 0) 132 { 133 // There is no possibility of overflowing the tm_day and tm_yday 134 // members because the date can be no later than January 19. 135 ptm->tm_wday = (ptm->tm_wday + static_cast<int>(ltime)) % 7; 136 ptm->tm_mday += static_cast<int>(ltime); 137 ptm->tm_yday += static_cast<int>(ltime); 138 } 139 else if (ltime < 0) 140 { 141 // It is possible to underflow the tm_mday and tm_yday fields. If 142 // this happens, then the adjusted date must lie in December 1969: 143 ptm->tm_wday = (ptm->tm_wday + 7 + static_cast<int>(ltime)) % 7; 144 ptm->tm_mday += static_cast<int>(ltime); 145 if (ptm->tm_mday <= 0) 146 { 147 ptm->tm_mday += 31; 148 149 // Per assumption #4 above, the time zone can cause the date to 150 // underflow the epoch by more than a day. 151 ptm->tm_yday = ptm->tm_yday + static_cast<int>(ltime) + 365; 152 ptm->tm_mon = 11; 153 ptm->tm_year--; 154 } 155 else 156 { 157 ptm->tm_yday += static_cast<int>(ltime); 158 } 159 } 160 } 161 162 return 0; 163} 164 165extern "C" errno_t __cdecl _localtime32_s( 166 tm* const ptm, 167 __time32_t const* const ptime 168 ) 169{ 170 return common_localtime_s(ptm, ptime); 171} 172 173extern "C" errno_t __cdecl _localtime64_s( 174 tm* const ptm, 175 __time64_t const* const ptime 176 ) 177{ 178 return common_localtime_s(ptm, ptime); 179} 180 181 182 183// Converts a time_t value to a tm value containing the corresponding local time. 184// Returns a pointer to the thread-local tm buffer containing the result on 185// success; returns nullptr on failure. 186template <typename TimeType> 187_Success_(return != 0) 188static tm* __cdecl common_localtime(TimeType const* const ptime) throw() 189{ 190 typedef __crt_time_time_t_traits<TimeType> time_traits; 191 192 tm* const ptm = __getgmtimebuf(); 193 if (ptm == nullptr) 194 return nullptr; 195 196 errno_t const status = time_traits::localtime_s(ptm, ptime); 197 if (status != 0) 198 return nullptr; 199 200 return ptm; 201} 202 203extern "C" tm* __cdecl _localtime32(__time32_t const* const ptime) 204{ 205 return common_localtime(ptime); 206} 207 208extern "C" tm* __cdecl _localtime64(__time64_t const* const ptime) 209{ 210 return common_localtime(ptime); 211}