1 /*
2
3 Copyright (c) 2007-2008 Michael G Schwern
4
5 This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
6
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:
15
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 */
28
29 /* See http://code.google.com/p/y2038 for this code's origin */
30
31 /*
32
33 Programmers who have available to them 64-bit time values as a 'long
34 long' type can use localtime64_r() and gmtime64_r() which correctly
35 converts the time even on 32-bit systems. Whether you have 64-bit time
36 values will depend on the operating system.
37
38 localtime64_r() is a 64-bit equivalent of localtime_r().
39
40 gmtime64_r() is a 64-bit equivalent of gmtime_r().
41
42 */
43
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <time.h>
49 #include <errno.h>
50 #include "time64.h"
51
52 /* BIONIC_BEGIN */
53 /* the following are here to avoid exposing time64_config.h and
54 * other types in our public time64.h header
55 */
56 #include "time64_config.h"
57
58 /* Not everyone has gm/localtime_r(), provide a replacement */
59 #ifdef HAS_LOCALTIME_R
60 # define LOCALTIME_R(clock, result) localtime_r(clock, result)
61 #else
62 # define LOCALTIME_R(clock, result) fake_localtime_r(clock, result)
63 #endif
64 #ifdef HAS_GMTIME_R
65 # define GMTIME_R(clock, result) gmtime_r(clock, result)
66 #else
67 # define GMTIME_R(clock, result) fake_gmtime_r(clock, result)
68 #endif
69
70 typedef int64_t Int64;
71 typedef time64_t Time64_T;
72 typedef int64_t Year;
73 #define TM tm
74 /* BIONIC_END */
75
76 /* Spec says except for stftime() and the _r() functions, these
77 all return static memory. Stabbings! */
78 static struct TM Static_Return_Date;
79 static char Static_Return_String[35];
80
81 static const int days_in_month[2][12] = {
82 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
83 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
84 };
85
86 static const int julian_days_by_month[2][12] = {
87 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
88 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
89 };
90
91 static char const wday_name[7][3] = {
92 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
93 };
94
95 static char const mon_name[12][3] = {
96 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
97 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
98 };
99
100 static const int length_of_year[2] = { 365, 366 };
101
102 /* Some numbers relating to the gregorian cycle */
103 static const Year years_in_gregorian_cycle = 400;
104 #define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
105 static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
106
107 /* Year range we can trust the time funcitons with */
108 #define MAX_SAFE_YEAR 2037
109 #define MIN_SAFE_YEAR 1971
110
111 /* 28 year Julian calendar cycle */
112 #define SOLAR_CYCLE_LENGTH 28
113
114 /* Year cycle from MAX_SAFE_YEAR down. */
115 static const int safe_years_high[SOLAR_CYCLE_LENGTH] = {
116 2016, 2017, 2018, 2019,
117 2020, 2021, 2022, 2023,
118 2024, 2025, 2026, 2027,
119 2028, 2029, 2030, 2031,
120 2032, 2033, 2034, 2035,
121 2036, 2037, 2010, 2011,
122 2012, 2013, 2014, 2015
123 };
124
125 /* Year cycle from MIN_SAFE_YEAR up */
126 static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
127 1996, 1997, 1998, 1971,
128 1972, 1973, 1974, 1975,
129 1976, 1977, 1978, 1979,
130 1980, 1981, 1982, 1983,
131 1984, 1985, 1986, 1987,
132 1988, 1989, 1990, 1991,
133 1992, 1993, 1994, 1995,
134 };
135
136 /* This isn't used, but it's handy to look at */
137 static const int dow_year_start[SOLAR_CYCLE_LENGTH] = {
138 5, 0, 1, 2, /* 0 2016 - 2019 */
139 3, 5, 6, 0, /* 4 */
140 1, 3, 4, 5, /* 8 1996 - 1998, 1971*/
141 6, 1, 2, 3, /* 12 1972 - 1975 */
142 4, 6, 0, 1, /* 16 */
143 2, 4, 5, 6, /* 20 2036, 2037, 2010, 2011 */
144 0, 2, 3, 4 /* 24 2012, 2013, 2014, 2015 */
145 };
146
147 /* Let's assume people are going to be looking for dates in the future.
148 Let's provide some cheats so you can skip ahead.
149 This has a 4x speed boost when near 2008.
150 */
151 /* Number of days since epoch on Jan 1st, 2008 GMT */
152 #define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
153 #define CHEAT_YEARS 108
154
155 #define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
156 #define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
157
158 #ifdef USE_SYSTEM_LOCALTIME
159 # define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
160 (a) <= SYSTEM_LOCALTIME_MAX && \
161 (a) >= SYSTEM_LOCALTIME_MIN \
162 )
163 #else
164 # define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
165 #endif
166
167 #ifdef USE_SYSTEM_GMTIME
168 # define SHOULD_USE_SYSTEM_GMTIME(a) ( \
169 (a) <= SYSTEM_GMTIME_MAX && \
170 (a) >= SYSTEM_GMTIME_MIN \
171 )
172 #else
173 # define SHOULD_USE_SYSTEM_GMTIME(a) (0)
174 #endif
175
176 /* Multi varadic macros are a C99 thing, alas */
177 #ifdef TIME_64_DEBUG
178 # define TRACE(format) (fprintf(stderr, format))
179 # define TRACE1(format, var1) (fprintf(stderr, format, var1))
180 # define TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
181 # define TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
182 #else
183 # define TRACE(format) ((void)0)
184 # define TRACE1(format, var1) ((void)0)
185 # define TRACE2(format, var1, var2) ((void)0)
186 # define TRACE3(format, var1, var2, var3) ((void)0)
187 #endif
188
189
is_exception_century(Year year)190 static int is_exception_century(Year year)
191 {
192 int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
193 TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
194
195 return(is_exception);
196 }
197
198
199 /* timegm() is not in the C or POSIX spec, but it is such a useful
200 extension I would be remiss in leaving it out. Also I need it
201 for localtime64()
202 */
timegm64(const struct TM * date)203 Time64_T timegm64(const struct TM *date) {
204 Time64_T days = 0;
205 Time64_T seconds = 0;
206 Year year;
207 Year orig_year = (Year)date->tm_year;
208 int cycles = 0;
209
210 if( orig_year > 100 ) {
211 cycles = (orig_year - 100) / 400;
212 orig_year -= cycles * 400;
213 days += (Time64_T)cycles * days_in_gregorian_cycle;
214 }
215 else if( orig_year < -300 ) {
216 cycles = (orig_year - 100) / 400;
217 orig_year -= cycles * 400;
218 days += (Time64_T)cycles * days_in_gregorian_cycle;
219 }
220 TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);
221
222 if( orig_year > 70 ) {
223 year = 70;
224 while( year < orig_year ) {
225 days += length_of_year[IS_LEAP(year)];
226 year++;
227 }
228 }
229 else if ( orig_year < 70 ) {
230 year = 69;
231 do {
232 days -= length_of_year[IS_LEAP(year)];
233 year--;
234 } while( year >= orig_year );
235 }
236
237
238 days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
239 days += date->tm_mday - 1;
240
241 seconds = days * 60 * 60 * 24;
242
243 seconds += date->tm_hour * 60 * 60;
244 seconds += date->tm_min * 60;
245 seconds += date->tm_sec;
246
247 return(seconds);
248 }
249
250
check_tm(struct TM * tm)251 static int check_tm(struct TM *tm)
252 {
253 /* Don't forget leap seconds */
254 assert(tm->tm_sec >= 0);
255 assert(tm->tm_sec <= 61);
256
257 assert(tm->tm_min >= 0);
258 assert(tm->tm_min <= 59);
259
260 assert(tm->tm_hour >= 0);
261 assert(tm->tm_hour <= 23);
262
263 assert(tm->tm_mday >= 1);
264 assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
265
266 assert(tm->tm_mon >= 0);
267 assert(tm->tm_mon <= 11);
268
269 assert(tm->tm_wday >= 0);
270 assert(tm->tm_wday <= 6);
271
272 assert(tm->tm_yday >= 0);
273 assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
274
275 #ifdef HAS_TM_TM_GMTOFF
276 assert(tm->tm_gmtoff >= -24 * 60 * 60);
277 assert(tm->tm_gmtoff <= 24 * 60 * 60);
278 #endif
279
280 return 1;
281 }
282
283
284 /* The exceptional centuries without leap years cause the cycle to
285 shift by 16
286 */
cycle_offset(Year year)287 static Year cycle_offset(Year year)
288 {
289 const Year start_year = 2000;
290 Year year_diff = year - start_year;
291 Year exceptions;
292
293 if( year > start_year )
294 year_diff--;
295
296 exceptions = year_diff / 100;
297 exceptions -= year_diff / 400;
298
299 TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
300 year, exceptions, year_diff);
301
302 return exceptions * 16;
303 }
304
305 /* For a given year after 2038, pick the latest possible matching
306 year in the 28 year calendar cycle.
307
308 A matching year...
309 1) Starts on the same day of the week.
310 2) Has the same leap year status.
311
312 This is so the calendars match up.
313
314 Also the previous year must match. When doing Jan 1st you might
315 wind up on Dec 31st the previous year when doing a -UTC time zone.
316
317 Finally, the next year must have the same start day of week. This
318 is for Dec 31st with a +UTC time zone.
319 It doesn't need the same leap year status since we only care about
320 January 1st.
321 */
safe_year(const Year year)322 static int safe_year(const Year year)
323 {
324 int safe_year = 0;
325 Year year_cycle;
326
327 if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) {
328 return (int)year;
329 }
330
331 year_cycle = year + cycle_offset(year);
332
333 /* safe_years_low is off from safe_years_high by 8 years */
334 if( year < MIN_SAFE_YEAR )
335 year_cycle -= 8;
336
337 /* Change non-leap xx00 years to an equivalent */
338 if( is_exception_century(year) )
339 year_cycle += 11;
340
341 /* Also xx01 years, since the previous year will be wrong */
342 if( is_exception_century(year - 1) )
343 year_cycle += 17;
344
345 year_cycle %= SOLAR_CYCLE_LENGTH;
346 if( year_cycle < 0 )
347 year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
348
349 assert( year_cycle >= 0 );
350 assert( year_cycle < SOLAR_CYCLE_LENGTH );
351 if( year < MIN_SAFE_YEAR )
352 safe_year = safe_years_low[year_cycle];
353 else if( year > MAX_SAFE_YEAR )
354 safe_year = safe_years_high[year_cycle];
355 else
356 assert(0);
357
358 TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
359 year, year_cycle, safe_year);
360
361 assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR);
362
363 return safe_year;
364 }
365
366
copy_tm_to_TM(const struct tm * src,struct TM * dest)367 static void copy_tm_to_TM(const struct tm *src, struct TM *dest) {
368 if( src == NULL ) {
369 memset(dest, 0, sizeof(*dest));
370 }
371 else {
372 # ifdef USE_TM64
373 dest->tm_sec = src->tm_sec;
374 dest->tm_min = src->tm_min;
375 dest->tm_hour = src->tm_hour;
376 dest->tm_mday = src->tm_mday;
377 dest->tm_mon = src->tm_mon;
378 dest->tm_year = (Year)src->tm_year;
379 dest->tm_wday = src->tm_wday;
380 dest->tm_yday = src->tm_yday;
381 dest->tm_isdst = src->tm_isdst;
382
383 # ifdef HAS_TM_TM_GMTOFF
384 dest->tm_gmtoff = src->tm_gmtoff;
385 # endif
386
387 # ifdef HAS_TM_TM_ZONE
388 dest->tm_zone = src->tm_zone;
389 # endif
390
391 # else
392 /* They're the same type */
393 memcpy(dest, src, sizeof(*dest));
394 # endif
395 }
396 }
397
398
copy_TM_to_tm(const struct TM * src,struct tm * dest)399 static void copy_TM_to_tm(const struct TM *src, struct tm *dest) {
400 if( src == NULL ) {
401 memset(dest, 0, sizeof(*dest));
402 }
403 else {
404 # ifdef USE_TM64
405 dest->tm_sec = src->tm_sec;
406 dest->tm_min = src->tm_min;
407 dest->tm_hour = src->tm_hour;
408 dest->tm_mday = src->tm_mday;
409 dest->tm_mon = src->tm_mon;
410 dest->tm_year = (int)src->tm_year;
411 dest->tm_wday = src->tm_wday;
412 dest->tm_yday = src->tm_yday;
413 dest->tm_isdst = src->tm_isdst;
414
415 # ifdef HAS_TM_TM_GMTOFF
416 dest->tm_gmtoff = src->tm_gmtoff;
417 # endif
418
419 # ifdef HAS_TM_TM_ZONE
420 dest->tm_zone = src->tm_zone;
421 # endif
422
423 # else
424 /* They're the same type */
425 memcpy(dest, src, sizeof(*dest));
426 # endif
427 }
428 }
429
430
431 /* Simulate localtime_r() to the best of our ability */
fake_localtime_r(const time_t * clock,struct tm * result)432 struct tm * fake_localtime_r(const time_t *clock, struct tm *result) {
433 const struct tm *static_result = localtime(clock);
434
435 assert(result != NULL);
436
437 if( static_result == NULL ) {
438 memset(result, 0, sizeof(*result));
439 return NULL;
440 }
441 else {
442 memcpy(result, static_result, sizeof(*result));
443 return result;
444 }
445 }
446
447
448
449 /* Simulate gmtime_r() to the best of our ability */
fake_gmtime_r(const time_t * clock,struct tm * result)450 struct tm * fake_gmtime_r(const time_t *clock, struct tm *result) {
451 const struct tm *static_result = gmtime(clock);
452
453 assert(result != NULL);
454
455 if( static_result == NULL ) {
456 memset(result, 0, sizeof(*result));
457 return NULL;
458 }
459 else {
460 memcpy(result, static_result, sizeof(*result));
461 return result;
462 }
463 }
464
465
seconds_between_years(Year left_year,Year right_year)466 static Time64_T seconds_between_years(Year left_year, Year right_year) {
467 int increment = (left_year > right_year) ? 1 : -1;
468 Time64_T seconds = 0;
469 int cycles;
470
471 if( left_year > 2400 ) {
472 cycles = (left_year - 2400) / 400;
473 left_year -= cycles * 400;
474 seconds += cycles * seconds_in_gregorian_cycle;
475 }
476 else if( left_year < 1600 ) {
477 cycles = (left_year - 1600) / 400;
478 left_year += cycles * 400;
479 seconds += cycles * seconds_in_gregorian_cycle;
480 }
481
482 while( left_year != right_year ) {
483 seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
484 right_year += increment;
485 }
486
487 return seconds * increment;
488 }
489
490
mktime64(const struct TM * input_date)491 Time64_T mktime64(const struct TM *input_date) {
492 struct tm safe_date;
493 struct TM date;
494 Time64_T time;
495 Year year = input_date->tm_year + 1900;
496
497 if( MIN_SAFE_YEAR <= year && year <= MAX_SAFE_YEAR ) {
498 copy_TM_to_tm(input_date, &safe_date);
499 return (Time64_T)mktime(&safe_date);
500 }
501
502 /* Have to make the year safe in date else it won't fit in safe_date */
503 date = *input_date;
504 date.tm_year = safe_year(year) - 1900;
505 copy_TM_to_tm(&date, &safe_date);
506
507 time = (Time64_T)mktime(&safe_date);
508
509 time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
510
511 return time;
512 }
513
514
515 /* Because I think mktime() is a crappy name */
timelocal64(const struct TM * date)516 Time64_T timelocal64(const struct TM *date) {
517 return mktime64(date);
518 }
519
520
gmtime64_r(const Time64_T * in_time,struct TM * p)521 struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
522 {
523 int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
524 Time64_T v_tm_tday;
525 int leap;
526 Time64_T m;
527 Time64_T time = *in_time;
528 Year year = 70;
529 int cycles = 0;
530
531 assert(p != NULL);
532
533 /* Use the system gmtime() if time_t is small enough */
534 if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
535 time_t safe_time = *in_time;
536 struct tm safe_date;
537 GMTIME_R(&safe_time, &safe_date);
538
539 copy_tm_to_TM(&safe_date, p);
540 assert(check_tm(p));
541
542 return p;
543 }
544
545 #ifdef HAS_TM_TM_GMTOFF
546 p->tm_gmtoff = 0;
547 #endif
548 p->tm_isdst = 0;
549
550 #ifdef HAS_TM_TM_ZONE
551 p->tm_zone = "UTC";
552 #endif
553
554 v_tm_sec = (int)(time % 60);
555 time /= 60;
556 v_tm_min = (int)(time % 60);
557 time /= 60;
558 v_tm_hour = (int)(time % 24);
559 time /= 24;
560 v_tm_tday = time;
561
562 WRAP (v_tm_sec, v_tm_min, 60);
563 WRAP (v_tm_min, v_tm_hour, 60);
564 WRAP (v_tm_hour, v_tm_tday, 24);
565
566 v_tm_wday = (int)((v_tm_tday + 4) % 7);
567 if (v_tm_wday < 0)
568 v_tm_wday += 7;
569 m = v_tm_tday;
570
571 if (m >= CHEAT_DAYS) {
572 year = CHEAT_YEARS;
573 m -= CHEAT_DAYS;
574 }
575
576 if (m >= 0) {
577 /* Gregorian cycles, this is huge optimization for distant times */
578 cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
579 if( cycles ) {
580 m -= (cycles * (Time64_T) days_in_gregorian_cycle);
581 year += (cycles * years_in_gregorian_cycle);
582 }
583
584 /* Years */
585 leap = IS_LEAP (year);
586 while (m >= (Time64_T) length_of_year[leap]) {
587 m -= (Time64_T) length_of_year[leap];
588 year++;
589 leap = IS_LEAP (year);
590 }
591
592 /* Months */
593 v_tm_mon = 0;
594 while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
595 m -= (Time64_T) days_in_month[leap][v_tm_mon];
596 v_tm_mon++;
597 }
598 } else {
599 year--;
600
601 /* Gregorian cycles */
602 cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
603 if( cycles ) {
604 m -= (cycles * (Time64_T) days_in_gregorian_cycle);
605 year += (cycles * years_in_gregorian_cycle);
606 }
607
608 /* Years */
609 leap = IS_LEAP (year);
610 while (m < (Time64_T) -length_of_year[leap]) {
611 m += (Time64_T) length_of_year[leap];
612 year--;
613 leap = IS_LEAP (year);
614 }
615
616 /* Months */
617 v_tm_mon = 11;
618 while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
619 m += (Time64_T) days_in_month[leap][v_tm_mon];
620 v_tm_mon--;
621 }
622 m += (Time64_T) days_in_month[leap][v_tm_mon];
623 }
624
625 p->tm_year = year;
626 if( p->tm_year != year ) {
627 #ifdef EOVERFLOW
628 errno = EOVERFLOW;
629 #endif
630 return NULL;
631 }
632
633 /* At this point m is less than a year so casting to an int is safe */
634 p->tm_mday = (int) m + 1;
635 p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
636 p->tm_sec = v_tm_sec;
637 p->tm_min = v_tm_min;
638 p->tm_hour = v_tm_hour;
639 p->tm_mon = v_tm_mon;
640 p->tm_wday = v_tm_wday;
641
642 assert(check_tm(p));
643
644 return p;
645 }
646
647
localtime64_r(const Time64_T * time,struct TM * local_tm)648 struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
649 {
650 time_t safe_time;
651 struct tm safe_date;
652 struct TM gm_tm;
653 Year orig_year;
654 int month_diff;
655
656 assert(local_tm != NULL);
657
658 /* Use the system localtime() if time_t is small enough */
659 if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
660 safe_time = *time;
661
662 TRACE1("Using system localtime for %lld\n", *time);
663
664 LOCALTIME_R(&safe_time, &safe_date);
665
666 copy_tm_to_TM(&safe_date, local_tm);
667 assert(check_tm(local_tm));
668
669 return local_tm;
670 }
671
672 if( gmtime64_r(time, &gm_tm) == NULL ) {
673 TRACE1("gmtime64_r returned null for %lld\n", *time);
674 return NULL;
675 }
676
677 orig_year = gm_tm.tm_year;
678
679 if (gm_tm.tm_year > (2037 - 1900) ||
680 gm_tm.tm_year < (1970 - 1900)
681 )
682 {
683 TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
684 gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
685 }
686
687 safe_time = timegm64(&gm_tm);
688 if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
689 TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
690 return NULL;
691 }
692
693 copy_tm_to_TM(&safe_date, local_tm);
694
695 local_tm->tm_year = orig_year;
696 if( local_tm->tm_year != orig_year ) {
697 TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
698 (Year)local_tm->tm_year, (Year)orig_year);
699
700 #ifdef EOVERFLOW
701 errno = EOVERFLOW;
702 #endif
703 return NULL;
704 }
705
706
707 month_diff = local_tm->tm_mon - gm_tm.tm_mon;
708
709 /* When localtime is Dec 31st previous year and
710 gmtime is Jan 1st next year.
711 */
712 if( month_diff == 11 ) {
713 local_tm->tm_year--;
714 }
715
716 /* When localtime is Jan 1st, next year and
717 gmtime is Dec 31st, previous year.
718 */
719 if( month_diff == -11 ) {
720 local_tm->tm_year++;
721 }
722
723 /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
724 in a non-leap xx00. There is one point in the cycle
725 we can't account for which the safe xx00 year is a leap
726 year. So we need to correct for Dec 31st comming out as
727 the 366th day of the year.
728 */
729 if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
730 local_tm->tm_yday--;
731
732 assert(check_tm(local_tm));
733
734 return local_tm;
735 }
736
737
valid_tm_wday(const struct TM * date)738 static int valid_tm_wday( const struct TM* date ) {
739 if( 0 <= date->tm_wday && date->tm_wday <= 6 )
740 return 1;
741 else
742 return 0;
743 }
744
valid_tm_mon(const struct TM * date)745 static int valid_tm_mon( const struct TM* date ) {
746 if( 0 <= date->tm_mon && date->tm_mon <= 11 )
747 return 1;
748 else
749 return 0;
750 }
751
752
asctime64_r(const struct TM * date,char * result)753 char *asctime64_r( const struct TM* date, char *result ) {
754 /* I figure everything else can be displayed, even hour 25, but if
755 these are out of range we walk off the name arrays */
756 if( !valid_tm_wday(date) || !valid_tm_mon(date) )
757 return NULL;
758
759 sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
760 wday_name[date->tm_wday],
761 mon_name[date->tm_mon],
762 date->tm_mday, date->tm_hour,
763 date->tm_min, date->tm_sec,
764 1900 + date->tm_year);
765
766 return result;
767 }
768
769
ctime64_r(const Time64_T * time,char * result)770 char *ctime64_r( const Time64_T* time, char* result ) {
771 struct TM date;
772
773 localtime64_r( time, &date );
774 return asctime64_r( &date, result );
775 }
776
777
778 /* Non-thread safe versions of the above */
localtime64(const Time64_T * time)779 struct TM *localtime64(const Time64_T *time) {
780 return localtime64_r(time, &Static_Return_Date);
781 }
782
gmtime64(const Time64_T * time)783 struct TM *gmtime64(const Time64_T *time) {
784 return gmtime64_r(time, &Static_Return_Date);
785 }
786
asctime64(const struct TM * date)787 char *asctime64( const struct TM* date ) {
788 return asctime64_r( date, Static_Return_String );
789 }
790
ctime64(const Time64_T * time)791 char *ctime64( const Time64_T* time ) {
792 return asctime64(localtime64(time));
793 }
794