Home | History | Annotate | Download | only in bionic
      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 
    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 */
    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 
    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 */
    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 */
    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 
    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 
    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 */
    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 */
    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 
    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 
    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 */
    516 Time64_T timelocal64(const struct TM *date) {
    517     return mktime64(date);
    518 }
    519 
    520 
    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 
    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 
    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 
    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 
    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 
    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 */
    779 struct TM *localtime64(const Time64_T *time) {
    780     return localtime64_r(time, &Static_Return_Date);
    781 }
    782 
    783 struct TM *gmtime64(const Time64_T *time) {
    784     return gmtime64_r(time, &Static_Return_Date);
    785 }
    786 
    787 char *asctime64( const struct TM* date ) {
    788     return asctime64_r( date, Static_Return_String );
    789 }
    790 
    791 char *ctime64( const Time64_T* time ) {
    792     return asctime64(localtime64(time));
    793 }
    794