Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 588 lines (464 sloc) 16.212 kB
e0ad44e @schwern r60997@windhund: schwern | 2008-09-11 03:51:57 -0700
authored
1 /*
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
2
e0ad44e @schwern r60997@windhund: schwern | 2008-09-11 03:51:57 -0700
authored
3 Copyright (c) 2007-2008 Michael G Schwern
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
4
e0ad44e @schwern r60997@windhund: schwern | 2008-09-11 03:51:57 -0700
authored
5 This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
6
e0ad44e @schwern r60997@windhund: schwern | 2008-09-11 03:51:57 -0700
authored
7 The MIT License:
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
15
e0ad44e @schwern r60997@windhund: schwern | 2008-09-11 03:51:57 -0700
authored
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26
27 */
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
28
29 /*
30
31 Programmers who have available to them 64-bit time values as a 'long
32 long' type can use localtime64_r() and gmtime64_r() which correctly
33 converts the time even on 32-bit systems. Whether you have 64-bit time
34 values will depend on the operating system.
35
36 localtime64_r() is a 64-bit equivalent of localtime_r().
37
38 gmtime64_r() is a 64-bit equivalent of gmtime_r().
39
40 */
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <stdio.h>
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
45 #include <string.h>
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
46 #include <time.h>
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
47 #include <errno.h>
f0726d9 @schwern r67108@windhund: schwern | 2008-09-29 15:51:31 -0400
authored
48 #include "time64.h"
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
49
50 static const int days_in_month[2][12] = {
51 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
52 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
53 };
54
55 static const int julian_days_by_month[2][12] = {
56 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
57 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
58 };
59
60 static const int length_of_year[2] = { 365, 366 };
61
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
62 /* Number of days in a 400 year Gregorian cycle */
d95058a @schwern r67119@windhund: schwern | 2008-09-30 01:22:47 -0400
authored
63 static const Year years_in_gregorian_cycle = 400;
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
64 static const int days_in_gregorian_cycle = (365 * 400) + 100 - 4 + 1;
65
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
66 /* 28 year calendar cycle between 2010 and 2037 */
12addb7 @schwern r67139@windhund: schwern | 2008-10-02 14:43:35 -0400
authored
67 #define SOLAR_CYCLE_LENGTH 28
68 static const int safe_years[SOLAR_CYCLE_LENGTH] = {
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
69 2016, 2017, 2018, 2019,
70 2020, 2021, 2022, 2023,
71 2024, 2025, 2026, 2027,
72 2028, 2029, 2030, 2031,
73 2032, 2033, 2034, 2035,
74 2036, 2037, 2010, 2011,
75 2012, 2013, 2014, 2015
76 };
77
e0dd59a @schwern r61041@windhund: schwern | 2008-09-14 21:29:37 -0700
authored
78 static const int dow_year_start[SOLAR_CYCLE_LENGTH] = {
24864cd @schwern r61043@windhund: schwern | 2008-09-15 19:24:10 -0700
authored
79 5, 0, 1, 2, /* 0 2016 - 2019 */
80 3, 5, 6, 0, /* 4 */
81 1, 3, 4, 5, /* 8 */
82 6, 1, 2, 3, /* 12 */
83 4, 6, 0, 1, /* 16 */
84 2, 4, 5, 6, /* 20 2036, 2037, 2010, 2011 */
85 0, 2, 3, 4 /* 24 2012, 2013, 2014, 2015 */
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
86 };
87
7c5ceaa @schwern r61016@windhund: schwern | 2008-09-11 17:03:58 -0700
authored
88 /* Let's assume people are going to be looking for dates in the future.
89 Let's provide some cheats so you can skip ahead.
90 This has a 4x speed boost when near 2008.
91 */
92 /* Number of days since epoch on Jan 1st, 2008 GMT */
93 #define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
94 #define CHEAT_YEARS 108
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
95
96 #define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
97 #define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
98
4d08c3c @schwern Move user configuration stuff into a new file.
authored
99 #ifdef USE_SYSTEM_LOCALTIME
100 # define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
9dc7284 @schwern r61033@windhund: schwern | 2008-09-14 14:39:16 -0700
authored
101 (a) <= SYSTEM_LOCALTIME_MAX && \
102 (a) >= SYSTEM_LOCALTIME_MIN \
103 )
4d08c3c @schwern Move user configuration stuff into a new file.
authored
104 #else
105 # define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
106 #endif
107
108 #ifdef USE_SYSTEM_GMTIME
109 # define SHOULD_USE_SYSTEM_GMTIME(a) ( \
9dc7284 @schwern r61033@windhund: schwern | 2008-09-14 14:39:16 -0700
authored
110 (a) <= SYSTEM_GMTIME_MAX && \
111 (a) >= SYSTEM_GMTIME_MIN \
112 )
4d08c3c @schwern Move user configuration stuff into a new file.
authored
113 #else
114 # define SHOULD_USE_SYSTEM_GMTIME(a) (0)
115 #endif
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
116
933caae @schwern Eliminate multi-var macros, that's C99
authored
117 /* Multi varadic macros are a C99 thing, alas */
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
118 #ifdef TIME_64_DEBUG
933caae @schwern Eliminate multi-var macros, that's C99
authored
119 # define TRACE(format) (fprintf(stderr, format))
120 # define TRACE1(format, var1) (fprintf(stderr, format, var1))
121 # define TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
122 # define TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
123 #else
933caae @schwern Eliminate multi-var macros, that's C99
authored
124 # define TRACE(format) ((void)0)
125 # define TRACE1(format, var1) ((void)0)
126 # define TRACE2(format, var1, var2) ((void)0)
127 # define TRACE3(format, var1, var2, var3) ((void)0)
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
128 #endif
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
129
6209e94 @schwern Change the last of the Int64 uses to more specific types.
authored
130 static int is_exception_century(Year year)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
131 {
132 int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
933caae @schwern Eliminate multi-var macros, that's C99
authored
133 TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
134
135 return(is_exception);
136 }
137
c86ccd8 @schwern r61013@windhund: schwern | 2008-09-11 16:11:17 -0700
authored
138
75d4f62 @schwern Consting.
authored
139 Time64_T timegm64(const struct TM *date) {
6209e94 @schwern Change the last of the Int64 uses to more specific types.
authored
140 int days = 0;
141 Time64_T seconds = 0;
142 Year year;
c86ccd8 @schwern r61013@windhund: schwern | 2008-09-11 16:11:17 -0700
authored
143
144 if( date->tm_year > 70 ) {
145 year = 70;
146 while( year < date->tm_year ) {
147 days += length_of_year[IS_LEAP(year)];
148 year++;
149 }
150 }
151 else if ( date->tm_year < 70 ) {
152 year = 69;
153 do {
154 days -= length_of_year[IS_LEAP(year)];
155 year--;
156 } while( year >= date->tm_year );
157 }
158
159 days += julian_days_by_month[IS_LEAP(date->tm_year)][date->tm_mon];
160 days += date->tm_mday - 1;
161
e0dd59a @schwern r61041@windhund: schwern | 2008-09-14 21:29:37 -0700
authored
162 /* Avoid overflowing the days integer */
163 seconds = days;
164 seconds = seconds * 60 * 60 * 24;
165
c86ccd8 @schwern r61013@windhund: schwern | 2008-09-11 16:11:17 -0700
authored
166 seconds += date->tm_hour * 60 * 60;
167 seconds += date->tm_min * 60;
168 seconds += date->tm_sec;
169
6209e94 @schwern Change the last of the Int64 uses to more specific types.
authored
170 return(seconds);
c86ccd8 @schwern r61013@windhund: schwern | 2008-09-11 16:11:17 -0700
authored
171 }
172
173
75f8055 @schwern r67111@windhund: schwern | 2008-09-29 17:28:17 -0400
authored
174 static int check_tm(struct TM *tm)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
175 {
176 /* Don't forget leap seconds */
34a9fd0 @schwern r61030@windhund: schwern | 2008-09-13 06:12:42 -0700
authored
177 assert(tm->tm_sec >= 0);
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
178 assert(tm->tm_sec <= 61);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
179
34a9fd0 @schwern r61030@windhund: schwern | 2008-09-13 06:12:42 -0700
authored
180 assert(tm->tm_min >= 0);
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
181 assert(tm->tm_min <= 59);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
182
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
183 assert(tm->tm_hour >= 0);
184 assert(tm->tm_hour <= 23);
185
186 assert(tm->tm_mday >= 1);
34a9fd0 @schwern r61030@windhund: schwern | 2008-09-13 06:12:42 -0700
authored
187 assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
188
189 assert(tm->tm_mon >= 0);
190 assert(tm->tm_mon <= 11);
191
192 assert(tm->tm_wday >= 0);
193 assert(tm->tm_wday <= 6);
194
195 assert(tm->tm_yday >= 0);
34a9fd0 @schwern r61030@windhund: schwern | 2008-09-13 06:12:42 -0700
authored
196 assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
197
198 #ifdef HAS_TM_TM_GMTOFF
199 assert(tm->tm_gmtoff >= -24 * 60 * 60);
200 assert(tm->tm_gmtoff <= 24 * 60 * 60);
201 #endif
34a9fd0 @schwern r61030@windhund: schwern | 2008-09-13 06:12:42 -0700
authored
202
203 return 1;
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
204 }
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
205
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
206
207 /* The exceptional centuries without leap years cause the cycle to
208 shift by 16
209 */
75f8055 @schwern r67111@windhund: schwern | 2008-09-29 17:28:17 -0400
authored
210 static Year cycle_offset(Year year)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
211 {
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
212 const Year start_year = 2000;
213 Year year_diff = year - start_year;
214 Year exceptions;
24864cd @schwern r61043@windhund: schwern | 2008-09-15 19:24:10 -0700
authored
215
216 if( year > start_year )
217 year_diff--;
218
9ae3981 @schwern r66448@windhund: schwern | 2008-09-24 17:15:10 -0400
authored
219 exceptions = year_diff / 100;
220 exceptions -= year_diff / 400;
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
221
933caae @schwern Eliminate multi-var macros, that's C99
authored
222 TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
223 year, exceptions, year_diff);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
224
225 return exceptions * 16;
226 }
227
228 /* For a given year after 2038, pick the latest possible matching
229 year in the 28 year calendar cycle.
e0dd59a @schwern r61041@windhund: schwern | 2008-09-14 21:29:37 -0700
authored
230
231 A matching year...
232 1) Starts on the same day of the week.
233 2) Has the same leap year status.
234
235 This is so the calendars match up.
236
237 Also the previous year must match. When doing Jan 1st you might
238 wind up on Dec 31st the previous year when doing a -UTC time zone.
24864cd @schwern r61043@windhund: schwern | 2008-09-15 19:24:10 -0700
authored
239
240 Finally, the next year must have the same start day of week. This
241 is for Dec 31st with a +UTC time zone.
242 It doesn't need the same leap year status since we only care about
243 January 1st.
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
244 */
75f8055 @schwern r67111@windhund: schwern | 2008-09-29 17:28:17 -0400
authored
245 static int safe_year(Year year)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
246 {
247 int safe_year;
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
248 Year year_cycle = year + cycle_offset(year);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
249
250 /* Change non-leap xx00 years to an equivalent */
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
251 if( is_exception_century(year) )
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
252 year_cycle += 11;
24864cd @schwern r61043@windhund: schwern | 2008-09-15 19:24:10 -0700
authored
253
254 /* Also xx01 years, since the previous year will be wrong */
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
255 if( is_exception_century(year - 1) )
24864cd @schwern r61043@windhund: schwern | 2008-09-15 19:24:10 -0700
authored
256 year_cycle += 17;
257
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
258 year_cycle %= SOLAR_CYCLE_LENGTH;
e0dd59a @schwern r61041@windhund: schwern | 2008-09-14 21:29:37 -0700
authored
259 if( year_cycle < 0 )
260 year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
261
24864cd @schwern r61043@windhund: schwern | 2008-09-15 19:24:10 -0700
authored
262 assert( year_cycle >= 0 );
263 assert( year_cycle < SOLAR_CYCLE_LENGTH );
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
264 safe_year = safe_years[year_cycle];
265
266 assert(safe_year <= 2037 && safe_year >= 2010);
267
933caae @schwern Eliminate multi-var macros, that's C99
authored
268 TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
269 year, year_cycle, safe_year);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
270
271 return safe_year;
272 }
273
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
274
0ac7075 @schwern r67112@windhund: schwern | 2008-09-29 18:58:30 -0400
authored
275 void copy_tm_to_TM(const struct tm *src, struct TM *dest) {
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
276 if( src == NULL ) {
277 memset(dest, 0, sizeof(*dest));
278 }
279 else {
280 # ifdef USE_TM64
281 dest->tm_sec = src->tm_sec;
282 dest->tm_min = src->tm_min;
283 dest->tm_hour = src->tm_hour;
284 dest->tm_mday = src->tm_mday;
285 dest->tm_mon = src->tm_mon;
286 dest->tm_year = (Year)src->tm_year;
287 dest->tm_wday = src->tm_wday;
288 dest->tm_yday = src->tm_yday;
289 dest->tm_isdst = src->tm_isdst;
290
291 # ifdef HAS_TM_TM_GMTOFF
292 dest->tm_gmtoff = src->tm_gmtoff;
293 # endif
294
295 # ifdef HAS_TM_TM_ZONE
df06b71 @schwern Turn on -Wconversion to catch conversion mistakes.
authored
296 dest->tm_zone = src->tm_zone;
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
297 # endif
298
299 # else
300 /* They're the same type */
301 memcpy(dest, src, sizeof(*dest));
302 # endif
303 }
304 }
305
306
0ac7075 @schwern r67112@windhund: schwern | 2008-09-29 18:58:30 -0400
authored
307 void copy_TM_to_tm(const struct TM *src, struct tm *dest) {
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
308 if( src == NULL ) {
309 memset(dest, 0, sizeof(*dest));
310 }
311 else {
312 # ifdef USE_TM64
313 dest->tm_sec = src->tm_sec;
314 dest->tm_min = src->tm_min;
315 dest->tm_hour = src->tm_hour;
316 dest->tm_mday = src->tm_mday;
317 dest->tm_mon = src->tm_mon;
318 dest->tm_year = (int)src->tm_year;
319 dest->tm_wday = src->tm_wday;
320 dest->tm_yday = src->tm_yday;
321 dest->tm_isdst = src->tm_isdst;
322
323 # ifdef HAS_TM_TM_GMTOFF
324 dest->tm_gmtoff = src->tm_gmtoff;
325 # endif
326
327 # ifdef HAS_TM_TM_ZONE
df06b71 @schwern Turn on -Wconversion to catch conversion mistakes.
authored
328 dest->tm_zone = src->tm_zone;
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
329 # endif
330
331 # else
332 /* They're the same type */
333 memcpy(dest, src, sizeof(*dest));
334 # endif
335 }
336 }
337
338
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
339 /* Simulate localtime_r() to the best of our ability */
0ac7075 @schwern r67112@windhund: schwern | 2008-09-29 18:58:30 -0400
authored
340 struct tm * fake_localtime_r(const time_t *clock, struct tm *result) {
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
341 const struct tm *static_result = localtime(clock);
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
342
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
343 assert(result != NULL);
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
344
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
345 if( static_result == NULL ) {
346 memset(result, 0, sizeof(*result));
347 return NULL;
348 }
349 else {
350 memcpy(result, static_result, sizeof(*result));
351 return result;
352 }
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
353 }
354
355
356 /* Simulate gmtime_r() to the best of our ability */
0ac7075 @schwern r67112@windhund: schwern | 2008-09-29 18:58:30 -0400
authored
357 struct tm * fake_gmtime_r(const time_t *clock, struct tm *result) {
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
358 const struct tm *static_result = gmtime(clock);
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
359
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
360 assert(result != NULL);
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
361
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
362 if( static_result == NULL ) {
363 memset(result, 0, sizeof(*result));
364 return NULL;
365 }
366 else {
367 memcpy(result, static_result, sizeof(*result));
368 return result;
369 }
75ef043 @schwern r66468@windhund: schwern | 2008-09-26 00:48:07 -0400
authored
370 }
371
372
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
373 struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
374 {
375 int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
9c13daf @schwern we don't need to use floor() or ceil(), integer math takes care of that.
authored
376 Time64_T v_tm_tday;
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
377 int leap;
9c13daf @schwern we don't need to use floor() or ceil(), integer math takes care of that.
authored
378 Time64_T m;
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
379 Time64_T time = *in_time;
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
380 Year year = 70;
d95058a @schwern r67119@windhund: schwern | 2008-09-30 01:22:47 -0400
authored
381 int cycles = 0;
25eaa3d @schwern r60992@windhund: schwern | 2008-09-10 23:34:22 -0700
authored
382
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
383 assert(p != NULL);
384
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
385 /* Use the system gmtime() if time_t is small enough */
386 if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
387 time_t safe_time = *in_time;
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
388 struct tm safe_date;
389 GMTIME_R(&safe_time, &safe_date);
390
391 copy_tm_to_TM(&safe_date, p);
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
392 assert(check_tm(p));
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
393
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
394 return p;
395 }
396
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
397 #ifdef HAS_TM_TM_GMTOFF
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
398 p->tm_gmtoff = 0;
25eaa3d @schwern r60992@windhund: schwern | 2008-09-10 23:34:22 -0700
authored
399 #endif
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
400 p->tm_isdst = 0;
25eaa3d @schwern r60992@windhund: schwern | 2008-09-10 23:34:22 -0700
authored
401
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
402 #ifdef HAS_TM_TM_ZONE
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
403 p->tm_zone = "UTC";
25eaa3d @schwern r60992@windhund: schwern | 2008-09-10 23:34:22 -0700
authored
404 #endif
405
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
406 v_tm_sec = (int)(time % 60);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
407 time /= 60;
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
408 v_tm_min = (int)(time % 60);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
409 time /= 60;
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
410 v_tm_hour = (int)(time % 24);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
411 time /= 24;
412 v_tm_tday = time;
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
413
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
414 WRAP (v_tm_sec, v_tm_min, 60);
415 WRAP (v_tm_min, v_tm_hour, 60);
416 WRAP (v_tm_hour, v_tm_tday, 24);
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
417
418 v_tm_wday = (int)((v_tm_tday + 4) % 7);
419 if (v_tm_wday < 0)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
420 v_tm_wday += 7;
421 m = v_tm_tday;
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
422
7c5ceaa @schwern r61016@windhund: schwern | 2008-09-11 17:03:58 -0700
authored
423 if (m >= CHEAT_DAYS) {
424 year = CHEAT_YEARS;
425 m -= CHEAT_DAYS;
426 }
427
428 if (m >= 0) {
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
429 /* Gregorian cycles, this is huge optimization for distant times */
d7c5113 @schwern Quiet a type conversion warning.
authored
430 cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
d95058a @schwern r67119@windhund: schwern | 2008-09-30 01:22:47 -0400
authored
431 if( cycles ) {
432 m -= (cycles * (Time64_T) days_in_gregorian_cycle);
433 year += (cycles * years_in_gregorian_cycle);
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
434 }
435
436 /* Years */
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
437 leap = IS_LEAP (year);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
438 while (m >= (Time64_T) length_of_year[leap]) {
439 m -= (Time64_T) length_of_year[leap];
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
440 year++;
441 leap = IS_LEAP (year);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
442 }
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
443
444 /* Months */
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
445 v_tm_mon = 0;
446 while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
447 m -= (Time64_T) days_in_month[leap][v_tm_mon];
448 v_tm_mon++;
449 }
450 } else {
7c5ceaa @schwern r61016@windhund: schwern | 2008-09-11 17:03:58 -0700
authored
451 year--;
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
452
453 /* Gregorian cycles */
d7c5113 @schwern Quiet a type conversion warning.
authored
454 cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
d95058a @schwern r67119@windhund: schwern | 2008-09-30 01:22:47 -0400
authored
455 if( cycles ) {
456 m -= (cycles * (Time64_T) days_in_gregorian_cycle);
457 year += (cycles * years_in_gregorian_cycle);
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
458 }
459
460 /* Years */
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
461 leap = IS_LEAP (year);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
462 while (m < (Time64_T) -length_of_year[leap]) {
463 m += (Time64_T) length_of_year[leap];
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
464 year--;
465 leap = IS_LEAP (year);
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
466 }
3a879e9 @schwern r60993@windhund: schwern | 2008-09-11 01:35:12 -0700
authored
467
468 /* Months */
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
469 v_tm_mon = 11;
470 while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
471 m += (Time64_T) days_in_month[leap][v_tm_mon];
472 v_tm_mon--;
473 }
474 m += (Time64_T) days_in_month[leap][v_tm_mon];
475 }
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
476
477 p->tm_year = year;
478 if( p->tm_year != year ) {
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
479 #ifdef EOVERFLOW
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
480 errno = EOVERFLOW;
27654fb @schwern r61018@windhund: schwern | 2008-09-13 02:58:57 -0700
authored
481 #endif
45e46b2 @schwern r60995@windhund: schwern | 2008-09-11 03:38:17 -0700
authored
482 return NULL;
483 }
484
4697651 @schwern Quiet on last type warning (on Windows).
authored
485 /* At this point m is less than a year so casting to an int is safe */
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
486 p->tm_mday = (int) m + 1;
4697651 @schwern Quiet on last type warning (on Windows).
authored
487 p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
488 p->tm_sec = v_tm_sec;
489 p->tm_min = v_tm_min;
490 p->tm_hour = v_tm_hour;
491 p->tm_mon = v_tm_mon;
492 p->tm_wday = v_tm_wday;
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
493
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
494 assert(check_tm(p));
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
495
496 return p;
497 }
498
499
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
500 struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
501 {
502 time_t safe_time;
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
503 struct tm safe_date;
504 struct TM gm_tm;
a26825a @schwern r66454@windhund: schwern | 2008-09-25 15:03:36 -0400
authored
505 Year orig_year;
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
506 int month_diff;
507
59f2c77 @schwern r67096@windhund: schwern | 2008-09-29 10:28:04 -0400
authored
508 assert(local_tm != NULL);
509
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
510 /* Use the system localtime() if time_t is small enough */
511 if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
512 safe_time = *time;
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
513
933caae @schwern Eliminate multi-var macros, that's C99
authored
514 TRACE1("Using system localtime for %lld\n", *time);
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
515
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
516 LOCALTIME_R(&safe_time, &safe_date);
517
518 copy_tm_to_TM(&safe_date, local_tm);
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
519 assert(check_tm(local_tm));
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
520
e1e20af @schwern r61024@windhund: schwern | 2008-09-13 04:17:41 -0700
authored
521 return local_tm;
522 }
523
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
524 if( gmtime64_r(time, &gm_tm) == NULL ) {
933caae @schwern Eliminate multi-var macros, that's C99
authored
525 TRACE1("gmtime64_r returned null for %lld\n", *time);
80c941e @schwern r61035@windhund: schwern | 2008-09-14 15:25:33 -0700
authored
526 return NULL;
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
527 }
80c941e @schwern r61035@windhund: schwern | 2008-09-14 15:25:33 -0700
authored
528
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
529 orig_year = gm_tm.tm_year;
530
5c64fde @schwern r61038@windhund: schwern | 2008-09-14 18:28:38 -0700
authored
531 if (gm_tm.tm_year > (2037 - 1900) ||
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
532 gm_tm.tm_year < (1970 - 1900)
5c64fde @schwern r61038@windhund: schwern | 2008-09-14 18:28:38 -0700
authored
533 )
534 {
933caae @schwern Eliminate multi-var macros, that's C99
authored
535 TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
e0d2108 @schwern Fix some more type conversion warnings revealed by turning USE_TM64 off.
authored
536 gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
5c64fde @schwern r61038@windhund: schwern | 2008-09-14 18:28:38 -0700
authored
537 }
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
538
df06b71 @schwern Turn on -Wconversion to catch conversion mistakes.
authored
539 safe_time = timegm64(&gm_tm);
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
540 if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
933caae @schwern Eliminate multi-var macros, that's C99
authored
541 TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
80c941e @schwern r61035@windhund: schwern | 2008-09-14 15:25:33 -0700
authored
542 return NULL;
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
543 }
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
544
14b7965 @schwern r67102@windhund: schwern | 2008-09-29 13:42:05 -0400
authored
545 copy_tm_to_TM(&safe_date, local_tm);
546
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
547 local_tm->tm_year = orig_year;
80c941e @schwern r61035@windhund: schwern | 2008-09-14 15:25:33 -0700
authored
548 if( local_tm->tm_year != orig_year ) {
933caae @schwern Eliminate multi-var macros, that's C99
authored
549 TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
a6bdcd5 @schwern Add some trace code to help with debugging.
authored
550 (Year)local_tm->tm_year, (Year)orig_year);
551
80c941e @schwern r61035@windhund: schwern | 2008-09-14 15:25:33 -0700
authored
552 #ifdef EOVERFLOW
553 errno = EOVERFLOW;
554 #endif
555 return NULL;
556 }
557
558
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
559 month_diff = local_tm->tm_mon - gm_tm.tm_mon;
560
561 /* When localtime is Dec 31st previous year and
562 gmtime is Jan 1st next year.
563 */
564 if( month_diff == 11 ) {
565 local_tm->tm_year--;
566 }
567
568 /* When localtime is Jan 1st, next year and
569 gmtime is Dec 31st, previous year.
570 */
571 if( month_diff == -11 ) {
572 local_tm->tm_year++;
573 }
574
575 /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
576 in a non-leap xx00. There is one point in the cycle
577 we can't account for which the safe xx00 year is a leap
578 year. So we need to correct for Dec 31st comming out as
579 the 366th day of the year.
580 */
581 if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
582 local_tm->tm_yday--;
583
db44efb @schwern r67110@windhund: schwern | 2008-09-29 17:25:49 -0400
authored
584 assert(check_tm(local_tm));
634d1c1 @schwern r60990@windhund: schwern | 2008-09-10 21:17:55 -0700
authored
585
586 return local_tm;
587 }
Something went wrong with that request. Please try again.