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 
mktime64(const struct TM * input_date)486 Time64_T mktime64(const struct TM *input_date) {
487     struct tm safe_date;
488     struct TM date;
489     Time64_T  time;
490     Year      year = input_date->tm_year + 1900;
491 
492     if( MIN_SAFE_YEAR <= year && year <= MAX_SAFE_YEAR ) {
493         copy_TM_to_tm(input_date, &safe_date);
494         return (Time64_T)mktime(&safe_date);
495     }
496 
497     /* Have to make the year safe in date else it won't fit in safe_date */
498     date = *input_date;
499     date.tm_year = safe_year(year) - 1900;
500     copy_TM_to_tm(&date, &safe_date);
501 
502     time = (Time64_T)mktime(&safe_date);
503 
504     time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
505 
506     return time;
507 }
508 
509 
510 /* Because I think mktime() is a crappy name */
timelocal64(const struct TM * date)511 Time64_T timelocal64(const struct TM *date) {
512     return mktime64(date);
513 }
514 
515 
gmtime64_r(const Time64_T * in_time,struct TM * p)516 struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
517 {
518     int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
519     Time64_T v_tm_tday;
520     int leap;
521     Time64_T m;
522     Time64_T time = *in_time;
523     Year year = 70;
524     int cycles = 0;
525 
526     assert(p != NULL);
527 
528     /* Use the system gmtime() if time_t is small enough */
529     if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
530         time_t safe_time = *in_time;
531         struct tm safe_date;
532         GMTIME_R(&safe_time, &safe_date);
533 
534         copy_tm_to_TM(&safe_date, p);
535         assert(check_tm(p));
536 
537         return p;
538     }
539 
540 #ifdef HAS_TM_TM_GMTOFF
541     p->tm_gmtoff = 0;
542 #endif
543     p->tm_isdst  = 0;
544 
545 #ifdef HAS_TM_TM_ZONE
546     p->tm_zone   = "UTC";
547 #endif
548 
549     v_tm_sec =  (int)(time % 60);
550     time /= 60;
551     v_tm_min =  (int)(time % 60);
552     time /= 60;
553     v_tm_hour = (int)(time % 24);
554     time /= 24;
555     v_tm_tday = time;
556 
557     WRAP (v_tm_sec, v_tm_min, 60);
558     WRAP (v_tm_min, v_tm_hour, 60);
559     WRAP (v_tm_hour, v_tm_tday, 24);
560 
561     v_tm_wday = (int)((v_tm_tday + 4) % 7);
562     if (v_tm_wday < 0)
563         v_tm_wday += 7;
564     m = v_tm_tday;
565 
566     if (m >= CHEAT_DAYS) {
567         year = CHEAT_YEARS;
568         m -= CHEAT_DAYS;
569     }
570 
571     if (m >= 0) {
572         /* Gregorian cycles, this is huge optimization for distant times */
573         cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
574         if( cycles ) {
575             m -= (cycles * (Time64_T) days_in_gregorian_cycle);
576             year += (cycles * years_in_gregorian_cycle);
577         }
578 
579         /* Years */
580         leap = IS_LEAP (year);
581         while (m >= (Time64_T) length_of_year[leap]) {
582             m -= (Time64_T) length_of_year[leap];
583             year++;
584             leap = IS_LEAP (year);
585         }
586 
587         /* Months */
588         v_tm_mon = 0;
589         while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
590             m -= (Time64_T) days_in_month[leap][v_tm_mon];
591             v_tm_mon++;
592         }
593     } else {
594         year--;
595 
596         /* Gregorian cycles */
597         cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
598         if( cycles ) {
599             m -= (cycles * (Time64_T) days_in_gregorian_cycle);
600             year += (cycles * years_in_gregorian_cycle);
601         }
602 
603         /* Years */
604         leap = IS_LEAP (year);
605         while (m < (Time64_T) -length_of_year[leap]) {
606             m += (Time64_T) length_of_year[leap];
607             year--;
608             leap = IS_LEAP (year);
609         }
610 
611         /* Months */
612         v_tm_mon = 11;
613         while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
614             m += (Time64_T) days_in_month[leap][v_tm_mon];
615             v_tm_mon--;
616         }
617         m += (Time64_T) days_in_month[leap][v_tm_mon];
618     }
619 
620     p->tm_year = year;
621     if( p->tm_year != year ) {
622 #ifdef EOVERFLOW
623         errno = EOVERFLOW;
624 #endif
625         return NULL;
626     }
627 
628     /* At this point m is less than a year so casting to an int is safe */
629     p->tm_mday = (int) m + 1;
630     p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
631     p->tm_sec  = v_tm_sec;
632     p->tm_min  = v_tm_min;
633     p->tm_hour = v_tm_hour;
634     p->tm_mon  = v_tm_mon;
635     p->tm_wday = v_tm_wday;
636 
637     assert(check_tm(p));
638 
639     return p;
640 }
641 
642 
localtime64_r(const Time64_T * time,struct TM * local_tm)643 struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
644 {
645     time_t safe_time;
646     struct tm safe_date;
647     struct TM gm_tm;
648     Year orig_year;
649     int month_diff;
650 
651     assert(local_tm != NULL);
652 
653     /* Use the system localtime() if time_t is small enough */
654     if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
655         safe_time = *time;
656 
657         TRACE1("Using system localtime for %lld\n", *time);
658 
659         LOCALTIME_R(&safe_time, &safe_date);
660 
661         copy_tm_to_TM(&safe_date, local_tm);
662         assert(check_tm(local_tm));
663 
664         return local_tm;
665     }
666 
667     if( gmtime64_r(time, &gm_tm) == NULL ) {
668         TRACE1("gmtime64_r returned null for %lld\n", *time);
669         return NULL;
670     }
671 
672     orig_year = gm_tm.tm_year;
673 
674     if (gm_tm.tm_year > (2037 - 1900) ||
675         gm_tm.tm_year < (1970 - 1900)
676        )
677     {
678         TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
679         gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
680     }
681 
682     safe_time = timegm64(&gm_tm);
683     if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
684         TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
685         return NULL;
686     }
687 
688     copy_tm_to_TM(&safe_date, local_tm);
689 
690     local_tm->tm_year = orig_year;
691     if( local_tm->tm_year != orig_year ) {
692         TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
693               (Year)local_tm->tm_year, (Year)orig_year);
694 
695 #ifdef EOVERFLOW
696         errno = EOVERFLOW;
697 #endif
698         return NULL;
699     }
700 
701 
702     month_diff = local_tm->tm_mon - gm_tm.tm_mon;
703 
704     /*  When localtime is Dec 31st previous year and
705         gmtime is Jan 1st next year.
706     */
707     if( month_diff == 11 ) {
708         local_tm->tm_year--;
709     }
710 
711     /*  When localtime is Jan 1st, next year and
712         gmtime is Dec 31st, previous year.
713     */
714     if( month_diff == -11 ) {
715         local_tm->tm_year++;
716     }
717 
718     /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
719        in a non-leap xx00.  There is one point in the cycle
720        we can't account for which the safe xx00 year is a leap
721        year.  So we need to correct for Dec 31st comming out as
722        the 366th day of the year.
723     */
724     if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
725         local_tm->tm_yday--;
726 
727     assert(check_tm(local_tm));
728 
729     return local_tm;
730 }
731 
732 
valid_tm_wday(const struct TM * date)733 static int valid_tm_wday( const struct TM* date ) {
734     if( 0 <= date->tm_wday && date->tm_wday <= 6 )
735         return 1;
736     else
737         return 0;
738 }
739 
valid_tm_mon(const struct TM * date)740 static int valid_tm_mon( const struct TM* date ) {
741     if( 0 <= date->tm_mon && date->tm_mon <= 11 )
742         return 1;
743     else
744         return 0;
745 }
746 
747 
asctime64_r(const struct TM * date,char * result)748 char *asctime64_r( const struct TM* date, char *result ) {
749     /* I figure everything else can be displayed, even hour 25, but if
750        these are out of range we walk off the name arrays */
751     if (!valid_tm_wday(date) || !valid_tm_mon(date)) {
752         return NULL;
753     }
754 
755     /* Docs state this function does not support years beyond 9999. */
756     if (1900 + date->tm_year > 9999) {
757         return NULL;
758     }
759 
760     /*
761      * The IBM docs for this function state that the result buffer can be
762      * assumed to be at least 26 bytes wide. The docs also state that this is
763      * only valid for years <= 9999, so we know this format string will not
764      * print more than that many characters.
765      *
766      * http://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/asctimer.htm
767      */
768     snprintf(result, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
769         wday_name[date->tm_wday],
770         mon_name[date->tm_mon],
771         date->tm_mday, date->tm_hour,
772         date->tm_min, date->tm_sec,
773         1900 + date->tm_year);
774 
775     return result;
776 }
777 
778 
ctime64_r(const Time64_T * time,char * result)779 char *ctime64_r( const Time64_T* time, char* result ) {
780     struct TM date;
781 
782     localtime64_r( time, &date );
783     return asctime64_r( &date, result );
784 }
785 
786 
787 /* Non-thread safe versions of the above */
localtime64(const Time64_T * time)788 struct TM *localtime64(const Time64_T *time) {
789     return localtime64_r(time, &Static_Return_Date);
790 }
791 
gmtime64(const Time64_T * time)792 struct TM *gmtime64(const Time64_T *time) {
793     return gmtime64_r(time, &Static_Return_Date);
794 }
795 
asctime64(const struct TM * date)796 char *asctime64( const struct TM* date ) {
797     return asctime64_r( date, Static_Return_String );
798 }
799 
ctime64(const Time64_T * time)800 char *ctime64( const Time64_T* time ) {
801     return asctime64(localtime64(time));
802 }
803