• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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