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