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 #if defined(__LP64__)
32 #error This cruft should be LP32 only!
33 #endif
34
35 /*
36
37 Programmers who have available to them 64-bit time values as a 'long
38 long' type can use localtime64_r() and gmtime64_r() which correctly
39 converts the time even on 32-bit systems. Whether you have 64-bit time
40 values will depend on the operating system.
41
42 localtime64_r() is a 64-bit equivalent of localtime_r().
43
44 gmtime64_r() is a 64-bit equivalent of gmtime_r().
45
46 */
47
48 #include <assert.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <time.h>
53 #include <errno.h>
54 #include "time64.h"
55
56 /* BIONIC_BEGIN */
57 /* the following are here to avoid exposing time64_config.h and
58 * other types in our public time64.h header
59 */
60 #include "time64_config.h"
61
62 /* Not everyone has gm/localtime_r(), provide a replacement */
63 #ifdef HAS_LOCALTIME_R
64 # define LOCALTIME_R(clock, result) localtime_r(clock, result)
65 #else
66 # define LOCALTIME_R(clock, result) fake_localtime_r(clock, result)
67 #endif
68 #ifdef HAS_GMTIME_R
69 # define GMTIME_R(clock, result) gmtime_r(clock, result)
70 #else
71 # define GMTIME_R(clock, result) fake_gmtime_r(clock, result)
72 #endif
73
74 typedef int64_t Int64;
75 typedef time64_t Time64_T;
76 typedef int64_t Year;
77 #define TM tm
78 /* BIONIC_END */
79
80 /* Spec says except for stftime() and the _r() functions, these
81 all return static memory. Stabbings! */
82 static struct TM Static_Return_Date;
83 static char Static_Return_String[35];
84
85 static const int days_in_month[2][12] = {
86 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
87 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
88 };
89
90 static const int julian_days_by_month[2][12] = {
91 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
92 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
93 };
94
95 static char const wday_name[7][3] = {
96 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
97 };
98
99 static char const mon_name[12][3] = {
100 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
101 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
102 };
103
104 static const int length_of_year[2] = { 365, 366 };
105
106 /* Some numbers relating to the gregorian cycle */
107 static const Year years_in_gregorian_cycle = 400;
108 #define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
109 static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
110
111 /* Year range we can trust the time funcitons with */
112 #define MAX_SAFE_YEAR 2037
113 #define MIN_SAFE_YEAR 1971
114
115 /* 28 year Julian calendar cycle */
116 #define SOLAR_CYCLE_LENGTH 28
117
118 /* Year cycle from MAX_SAFE_YEAR down. */
119 static const int safe_years_high[SOLAR_CYCLE_LENGTH] = {
120 2016, 2017, 2018, 2019,
121 2020, 2021, 2022, 2023,
122 2024, 2025, 2026, 2027,
123 2028, 2029, 2030, 2031,
124 2032, 2033, 2034, 2035,
125 2036, 2037, 2010, 2011,
126 2012, 2013, 2014, 2015
127 };
128
129 /* Year cycle from MIN_SAFE_YEAR up */
130 static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
131 1996, 1997, 1998, 1971,
132 1972, 1973, 1974, 1975,
133 1976, 1977, 1978, 1979,
134 1980, 1981, 1982, 1983,
135 1984, 1985, 1986, 1987,
136 1988, 1989, 1990, 1991,
137 1992, 1993, 1994, 1995,
138 };
139
140 /* Let's assume people are going to be looking for dates in the future.
141 Let's provide some cheats so you can skip ahead.
142 This has a 4x speed boost when near 2008.
143 */
144 /* Number of days since epoch on Jan 1st, 2008 GMT */
145 #define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
146 #define CHEAT_YEARS 108
147
148 #define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
149 #define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
150
151 #ifdef USE_SYSTEM_LOCALTIME
152 # define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
153 (a) <= SYSTEM_LOCALTIME_MAX && \
154 (a) >= SYSTEM_LOCALTIME_MIN \
155 )
156 #else
157 # define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
158 #endif
159
160 #ifdef USE_SYSTEM_GMTIME
161 # define SHOULD_USE_SYSTEM_GMTIME(a) ( \
162 (a) <= SYSTEM_GMTIME_MAX && \
163 (a) >= SYSTEM_GMTIME_MIN \
164 )
165 #else
166 # define SHOULD_USE_SYSTEM_GMTIME(a) (0)
167 #endif
168
169 /* Multi varadic macros are a C99 thing, alas */
170 #ifdef TIME_64_DEBUG
171 # define TRACE(format) (fprintf(stderr, format))
172 # define TRACE1(format, var1) (fprintf(stderr, format, var1))
173 # define TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
174 # define TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
175 #else
176 # define TRACE(format) ((void)0)
177 # define TRACE1(format, var1) ((void)0)
178 # define TRACE2(format, var1, var2) ((void)0)
179 # define TRACE3(format, var1, var2, var3) ((void)0)
180 #endif
181
182
is_exception_century(Year year)183 static int is_exception_century(Year year)
184 {
185 int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
186 TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
187
188 return(is_exception);
189 }
190
191
192 /* timegm() is not in the C or POSIX spec, but it is such a useful
193 extension I would be remiss in leaving it out. Also I need it
194 for localtime64()
195 */
timegm64(const struct TM * date)196 Time64_T timegm64(const struct TM *date) {
197 Time64_T days = 0;
198 Time64_T seconds = 0;
199 Year year;
200 Year orig_year = (Year)date->tm_year;
201 int cycles = 0;
202
203 if( orig_year > 100 ) {
204 cycles = (orig_year - 100) / 400;
205 orig_year -= cycles * 400;
206 days += (Time64_T)cycles * days_in_gregorian_cycle;
207 }
208 else if( orig_year < -300 ) {
209 cycles = (orig_year - 100) / 400;
210 orig_year -= cycles * 400;
211 days += (Time64_T)cycles * days_in_gregorian_cycle;
212 }
213 TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);
214
215 if( orig_year > 70 ) {
216 year = 70;
217 while( year < orig_year ) {
218 days += length_of_year[IS_LEAP(year)];
219 year++;
220 }
221 }
222 else if ( orig_year < 70 ) {
223 year = 69;
224 do {
225 days -= length_of_year[IS_LEAP(year)];
226 year--;
227 } while( year >= orig_year );
228 }
229
230
231 days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
232 days += date->tm_mday - 1;
233
234 seconds = days * 60 * 60 * 24;
235
236 seconds += date->tm_hour * 60 * 60;
237 seconds += date->tm_min * 60;
238 seconds += date->tm_sec;
239
240 return(seconds);
241 }
242
243
244 #if !defined(NDEBUG)
check_tm(struct TM * tm)245 static int check_tm(struct TM *tm)
246 {
247 /* Don't forget leap seconds */
248 assert(tm->tm_sec >= 0);
249 assert(tm->tm_sec <= 61);
250
251 assert(tm->tm_min >= 0);
252 assert(tm->tm_min <= 59);
253
254 assert(tm->tm_hour >= 0);
255 assert(tm->tm_hour <= 23);
256
257 assert(tm->tm_mday >= 1);
258 assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
259
260 assert(tm->tm_mon >= 0);
261 assert(tm->tm_mon <= 11);
262
263 assert(tm->tm_wday >= 0);
264 assert(tm->tm_wday <= 6);
265
266 assert(tm->tm_yday >= 0);
267 assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
268
269 #ifdef HAS_TM_TM_GMTOFF
270 assert(tm->tm_gmtoff >= -24 * 60 * 60);
271 assert(tm->tm_gmtoff <= 24 * 60 * 60);
272 #endif
273
274 return 1;
275 }
276 #endif
277
278
279 /* The exceptional centuries without leap years cause the cycle to
280 shift by 16
281 */
cycle_offset(Year year)282 static Year cycle_offset(Year year)
283 {
284 const Year start_year = 2000;
285 Year year_diff = year - start_year;
286 Year exceptions;
287
288 if( year > start_year )
289 year_diff--;
290
291 exceptions = year_diff / 100;
292 exceptions -= year_diff / 400;
293
294 TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
295 year, exceptions, year_diff);
296
297 return exceptions * 16;
298 }
299
300 /* For a given year after 2038, pick the latest possible matching
301 year in the 28 year calendar cycle.
302
303 A matching year...
304 1) Starts on the same day of the week.
305 2) Has the same leap year status.
306
307 This is so the calendars match up.
308
309 Also the previous year must match. When doing Jan 1st you might
310 wind up on Dec 31st the previous year when doing a -UTC time zone.
311
312 Finally, the next year must have the same start day of week. This
313 is for Dec 31st with a +UTC time zone.
314 It doesn't need the same leap year status since we only care about
315 January 1st.
316 */
safe_year(const Year year)317 static int safe_year(const Year year)
318 {
319 int safe_year = 0;
320 Year year_cycle;
321
322 if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) {
323 return (int)year;
324 }
325
326 year_cycle = year + cycle_offset(year);
327
328 /* safe_years_low is off from safe_years_high by 8 years */
329 if( year < MIN_SAFE_YEAR )
330 year_cycle -= 8;
331
332 /* Change non-leap xx00 years to an equivalent */
333 if( is_exception_century(year) )
334 year_cycle += 11;
335
336 /* Also xx01 years, since the previous year will be wrong */
337 if( is_exception_century(year - 1) )
338 year_cycle += 17;
339
340 year_cycle %= SOLAR_CYCLE_LENGTH;
341 if( year_cycle < 0 )
342 year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
343
344 assert( year_cycle >= 0 );
345 assert( year_cycle < SOLAR_CYCLE_LENGTH );
346 if( year < MIN_SAFE_YEAR )
347 safe_year = safe_years_low[year_cycle];
348 else if( year > MAX_SAFE_YEAR )
349 safe_year = safe_years_high[year_cycle];
350 else
351 assert(0);
352
353 TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
354 year, year_cycle, safe_year);
355
356 assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR);
357
358 return safe_year;
359 }
360
361
copy_tm_to_TM(const struct tm * src,struct TM * dest)362 static void copy_tm_to_TM(const struct tm *src, struct TM *dest) {
363 if( src == NULL ) {
364 memset(dest, 0, sizeof(*dest));
365 }
366 else {
367 # ifdef USE_TM64
368 dest->tm_sec = src->tm_sec;
369 dest->tm_min = src->tm_min;
370 dest->tm_hour = src->tm_hour;
371 dest->tm_mday = src->tm_mday;
372 dest->tm_mon = src->tm_mon;
373 dest->tm_year = (Year)src->tm_year;
374 dest->tm_wday = src->tm_wday;
375 dest->tm_yday = src->tm_yday;
376 dest->tm_isdst = src->tm_isdst;
377
378 # ifdef HAS_TM_TM_GMTOFF
379 dest->tm_gmtoff = src->tm_gmtoff;
380 # endif
381
382 # ifdef HAS_TM_TM_ZONE
383 dest->tm_zone = src->tm_zone;
384 # endif
385
386 # else
387 /* They're the same type */
388 memcpy(dest, src, sizeof(*dest));
389 # endif
390 }
391 }
392
393
copy_TM_to_tm(const struct TM * src,struct tm * dest)394 static void copy_TM_to_tm(const struct TM *src, struct tm *dest) {
395 if( src == NULL ) {
396 memset(dest, 0, sizeof(*dest));
397 }
398 else {
399 # ifdef USE_TM64
400 dest->tm_sec = src->tm_sec;
401 dest->tm_min = src->tm_min;
402 dest->tm_hour = src->tm_hour;
403 dest->tm_mday = src->tm_mday;
404 dest->tm_mon = src->tm_mon;
405 dest->tm_year = (int)src->tm_year;
406 dest->tm_wday = src->tm_wday;
407 dest->tm_yday = src->tm_yday;
408 dest->tm_isdst = src->tm_isdst;
409
410 # ifdef HAS_TM_TM_GMTOFF
411 dest->tm_gmtoff = src->tm_gmtoff;
412 # endif
413
414 # ifdef HAS_TM_TM_ZONE
415 dest->tm_zone = src->tm_zone;
416 # endif
417
418 # else
419 /* They're the same type */
420 memcpy(dest, src, sizeof(*dest));
421 # endif
422 }
423 }
424
425
426 /* Simulate localtime_r() to the best of our ability */
fake_localtime_r(const time_t * clock,struct tm * result)427 struct tm * fake_localtime_r(const time_t *clock, struct tm *result) {
428 const struct tm *static_result = localtime(clock);
429
430 assert(result != NULL);
431
432 if( static_result == NULL ) {
433 memset(result, 0, sizeof(*result));
434 return NULL;
435 }
436 else {
437 memcpy(result, static_result, sizeof(*result));
438 return result;
439 }
440 }
441
442
443
444 /* Simulate gmtime_r() to the best of our ability */
fake_gmtime_r(const time_t * clock,struct tm * result)445 struct tm * fake_gmtime_r(const time_t *clock, struct tm *result) {
446 const struct tm *static_result = gmtime(clock);
447
448 assert(result != NULL);
449
450 if( static_result == NULL ) {
451 memset(result, 0, sizeof(*result));
452 return NULL;
453 }
454 else {
455 memcpy(result, static_result, sizeof(*result));
456 return result;
457 }
458 }
459
460
seconds_between_years(Year left_year,Year right_year)461 static Time64_T seconds_between_years(Year left_year, Year right_year) {
462 int increment = (left_year > right_year) ? 1 : -1;
463 Time64_T seconds = 0;
464 int cycles;
465
466 if( left_year > 2400 ) {
467 cycles = (left_year - 2400) / 400;
468 left_year -= cycles * 400;
469 seconds += cycles * seconds_in_gregorian_cycle;
470 }
471 else if( left_year < 1600 ) {
472 cycles = (left_year - 1600) / 400;
473 left_year += cycles * 400;
474 seconds += cycles * seconds_in_gregorian_cycle;
475 }
476
477 while( left_year != right_year ) {
478 seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
479 right_year += increment;
480 }
481
482 return seconds * increment;
483 }
484
485
486 /* This implementation violates mktime specification, according to which
487 tm_yday, tm_wday, and tm_isdst fields should be updated. This function
488 leaves input_date unmodified. Given that there were no bug reports, fixing
489 it might cause more troubles than just leaving it as it is.
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
760 /* Docs state this function does not support years beyond 9999. */
761 if (1900 + date->tm_year > 9999) {
762 return NULL;
763 }
764
765 /*
766 * The IBM docs for this function state that the result buffer can be
767 * assumed to be at least 26 bytes wide. The docs also state that this is
768 * only valid for years <= 9999, so we know this format string will not
769 * print more than that many characters.
770 *
771 * http://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/asctimer.htm
772 */
773 snprintf(result, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
774 wday_name[date->tm_wday],
775 mon_name[date->tm_mon],
776 date->tm_mday, date->tm_hour,
777 date->tm_min, date->tm_sec,
778 1900 + date->tm_year);
779
780 return result;
781 }
782
783
ctime64_r(const Time64_T * time,char * result)784 char *ctime64_r( const Time64_T* time, char* result ) {
785 struct TM date;
786
787 localtime64_r( time, &date );
788 return asctime64_r( &date, result );
789 }
790
791
792 /* Non-thread safe versions of the above */
localtime64(const Time64_T * time)793 struct TM *localtime64(const Time64_T *time) {
794 return localtime64_r(time, &Static_Return_Date);
795 }
796
gmtime64(const Time64_T * time)797 struct TM *gmtime64(const Time64_T *time) {
798 return gmtime64_r(time, &Static_Return_Date);
799 }
800
asctime64(const struct TM * date)801 char *asctime64( const struct TM* date ) {
802 return asctime64_r( date, Static_Return_String );
803 }
804
ctime64(const Time64_T * time)805 char *ctime64( const Time64_T* time ) {
806 return asctime64(localtime64(time));
807 }
808