ReactOS 0.4.16-dev-1028-g8602629
localtime.cpp
Go to the documentation of this file.
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//
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>
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:
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;
55 _ERRCHECK(_get_dstbias (&dstbias ));
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
166 tm* const ptm,
167 __time32_t const* const ptime
168 )
169{
170 return common_localtime_s(ptm, ptime);
171}
172
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}
#define EINVAL
Definition: acclib.h:90
#define __cdecl
Definition: accygwin.h:79
#define _ERRCHECK(e)
void __cdecl __tzset()
Definition: tzset.cpp:392
int __cdecl _isindst(_In_ tm *_Time)
#define _DAY_SEC
tm *__cdecl __getgmtimebuf()
Definition: gmtime.cpp:154
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const _In_ bool const _Inout_ __crt_cached_ptd_host &ptd throw()
Definition: cvt.cpp:119
#define _VALIDATE_RETURN_ERRCODE(expr, errorcode)
#define _VALIDATE_RETURN_ERRCODE_NOEXC(expr, errorcode)
errno_t __cdecl _localtime32_s(tm *const ptm, __time32_t const *const ptime)
Definition: localtime.cpp:165
errno_t __cdecl _localtime64_s(tm *const ptm, __time64_t const *const ptime)
Definition: localtime.cpp:173
tm *__cdecl _localtime64(__time64_t const *const ptime)
Definition: localtime.cpp:208
static errno_t __cdecl common_localtime_s(tm *const ptm, TimeType const *const ptime)
Definition: localtime.cpp:33
tm *__cdecl _localtime32(__time32_t const *const ptime)
Definition: localtime.cpp:203
#define _Success_(c)
Definition: no_sal2.h:84
_CRTIMP errno_t __cdecl _get_daylight(_Out_ int *_Daylight)
_CRTIMP errno_t __cdecl _get_dstbias(_Out_ long *_Daylight_savings_bias)
_CRTIMP int daylight
_CRTIMP errno_t __cdecl _get_timezone(_Out_ long *_Timezone)
long __time32_t
Definition: time.h:24
#define memset(x, y, z)
Definition: compat.h:39
Definition: ps.c:97
Definition: fake.h:14
Definition: time.h:68
int errno_t
Definition: corecrt.h:615
__int64 __time64_t
Definition: corecrt.h:619
#define const
Definition: zconf.h:233