strftime.c revision 708c11205443cda14cfb21138d441106aa77a5f9
1/* 2** Based on the UCB version with the copyright notice and sccsid 3** appearing below. 4** 5** This is ANSIish only when "multibyte character == plain character". 6*/ 7 8#include "private.h" 9 10/* 11** Copyright (c) 1989 The Regents of the University of California. 12** All rights reserved. 13** 14** Redistribution and use in source and binary forms are permitted 15** provided that the above copyright notice and this paragraph are 16** duplicated in all such forms and that any documentation, 17** advertising materials, and other materials related to such 18** distribution and use acknowledge that the software was developed 19** by the University of California, Berkeley. The name of the 20** University may not be used to endorse or promote products derived 21** from this software without specific prior written permission. 22** THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 23** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 24** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 25*/ 26 27#include "tzfile.h" 28#include "fcntl.h" 29#include "locale.h" 30 31#if __ANDROID__ 32 33/* 34 * This has an extra standalone_month array field compared to upstream. 35 * We only need to keep that if we leave the strftime_tz symbol exposed. 36 * Even then, this structure was never in an NDK header file. 37 */ 38struct lc_time_T { 39 const char * mon[12]; 40 const char * month[12]; 41 const char * standalone_month[12]; 42 const char * wday[7]; 43 const char * weekday[7]; 44 const char * X_fmt; 45 const char * x_fmt; 46 const char * c_fmt; 47 const char * am; 48 const char * pm; 49 const char * date_fmt; 50}; 51 52/* LP32 had a 32-bit time_t, so we need to work around that here. */ 53#if defined(__LP64__) 54#define time64_t time_t 55#define mktime64 mktime 56#else 57#include <time64.h> 58#endif 59 60#include <ctype.h> 61 62size_t strftime_tz(char*, size_t, const char*, const struct tm*, const struct lc_time_T*); 63 64#else // not __ANDROID__ 65struct lc_time_T { 66 const char * mon[MONSPERYEAR]; 67 const char * month[MONSPERYEAR]; 68 const char * wday[DAYSPERWEEK]; 69 const char * weekday[DAYSPERWEEK]; 70 const char * X_fmt; 71 const char * x_fmt; 72 const char * c_fmt; 73 const char * am; 74 const char * pm; 75 const char * date_fmt; 76}; 77#endif 78 79#if LOCALE_HOME 80#include "sys/stat.h" 81static struct lc_time_T localebuf; 82static struct lc_time_T * _loc(void); 83#define Locale _loc() 84#endif /* defined LOCALE_HOME */ 85#ifndef LOCALE_HOME 86#define Locale (&C_time_locale) 87#endif /* !defined LOCALE_HOME */ 88 89static const struct lc_time_T C_time_locale = { 90 { 91 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 92 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 93 }, { 94 "January", "February", "March", "April", "May", "June", 95 "July", "August", "September", "October", "November", "December" 96 }, { 97 "January", "February", "March", "April", "May", "June", 98 "July", "August", "September", "October", "November", "December" 99 }, { 100 "Sun", "Mon", "Tue", "Wed", 101 "Thu", "Fri", "Sat" 102 }, { 103 "Sunday", "Monday", "Tuesday", "Wednesday", 104 "Thursday", "Friday", "Saturday" 105 }, 106 107 /* X_fmt */ 108 "%H:%M:%S", 109 110 /* 111 ** x_fmt 112 ** C99 requires this format. 113 ** Using just numbers (as here) makes Quakers happier; 114 ** it's also compatible with SVR4. 115 */ 116 "%m/%d/%y", 117 118 /* 119 ** c_fmt 120 ** C99 requires this format. 121 ** Previously this code used "%D %X", but we now conform to C99. 122 ** Note that 123 ** "%a %b %d %H:%M:%S %Y" 124 ** is used by Solaris 2.3. 125 */ 126 "%a %b %e %T %Y", 127 128 /* am */ 129 "AM", 130 131 /* pm */ 132 "PM", 133 134 /* date_fmt */ 135 "%a %b %e %H:%M:%S %Z %Y" 136}; 137 138static char * _add(const char *, char *, const char *, int); 139static char * _conv(int, const char *, char *, const char *); 140static char * _fmt(const char *, const struct tm *, char *, const char *, 141 int *, const struct lc_time_T*); 142static char * _yconv(int, int, int, int, char *, const char *, int); 143static char * getformat(int, char *, char *, char *, char *); 144 145extern char * tzname[]; 146 147#ifndef YEAR_2000_NAME 148#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS" 149#endif /* !defined YEAR_2000_NAME */ 150 151#define IN_NONE 0 152#define IN_SOME 1 153#define IN_THIS 2 154#define IN_ALL 3 155 156#define FORCE_LOWER_CASE 0x100 157 158size_t 159strftime(s, maxsize, format, t) 160char * const s; 161const size_t maxsize; 162const char * const format; 163const struct tm * const t; 164{ 165 return strftime_tz(s, maxsize, format, t, Locale); 166} 167 168__LIBC64_HIDDEN__ size_t strftime_tz(s, maxsize, format, t, locale) 169char * const s; 170const size_t maxsize; 171const char * const format; 172const struct tm * const t; 173const struct lc_time_T *locale; 174{ 175 char * p; 176 int warn; 177 178 tzset(); 179 warn = IN_NONE; 180 p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, locale); 181#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU 182 if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { 183 (void) fprintf(stderr, "\n"); 184 if (format == NULL) 185 (void) fprintf(stderr, "NULL strftime format "); 186 else (void) fprintf(stderr, "strftime format \"%s\" ", 187 format); 188 (void) fprintf(stderr, "yields only two digits of years in "); 189 if (warn == IN_SOME) 190 (void) fprintf(stderr, "some locales"); 191 else if (warn == IN_THIS) 192 (void) fprintf(stderr, "the current locale"); 193 else (void) fprintf(stderr, "all locales"); 194 (void) fprintf(stderr, "\n"); 195 } 196#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */ 197 if (p == s + maxsize) 198 return 0; 199 *p = '\0'; 200 return p - s; 201} 202 203static char *getformat(int modifier, char *normal, char *underscore, 204 char *dash, char *zero) { 205 switch (modifier) { 206 case '_': 207 return underscore; 208 209 case '-': 210 return dash; 211 212 case '0': 213 return zero; 214 } 215 216 return normal; 217} 218 219static char * 220_fmt(format, t, pt, ptlim, warnp, locale) 221const char * format; 222const struct tm * const t; 223char * pt; 224const char * const ptlim; 225int * warnp; 226const struct lc_time_T* locale; 227{ 228 for ( ; *format; ++format) { 229 if (*format == '%') { 230 int modifier = 0; 231label: 232 switch (*++format) { 233 case '\0': 234 --format; 235 break; 236 case 'A': 237 pt = _add((t->tm_wday < 0 || 238 t->tm_wday >= DAYSPERWEEK) ? 239 "?" : locale->weekday[t->tm_wday], 240 pt, ptlim, modifier); 241 continue; 242 case 'a': 243 pt = _add((t->tm_wday < 0 || 244 t->tm_wday >= DAYSPERWEEK) ? 245 "?" : locale->wday[t->tm_wday], 246 pt, ptlim, modifier); 247 continue; 248 case 'B': 249 if (modifier == '-') { 250 pt = _add((t->tm_mon < 0 || 251 t->tm_mon >= MONSPERYEAR) ? 252 "?" : locale->standalone_month[t->tm_mon], 253 pt, ptlim, modifier); 254 } else { 255 pt = _add((t->tm_mon < 0 || 256 t->tm_mon >= MONSPERYEAR) ? 257 "?" : locale->month[t->tm_mon], 258 pt, ptlim, modifier); 259 } 260 continue; 261 case 'b': 262 case 'h': 263 pt = _add((t->tm_mon < 0 || 264 t->tm_mon >= MONSPERYEAR) ? 265 "?" : locale->mon[t->tm_mon], 266 pt, ptlim, modifier); 267 continue; 268 case 'C': 269 /* 270 ** %C used to do a... 271 ** _fmt("%a %b %e %X %Y", t); 272 ** ...whereas now POSIX 1003.2 calls for 273 ** something completely different. 274 ** (ado, 1993-05-24) 275 */ 276 pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0, 277 pt, ptlim, modifier); 278 continue; 279 case 'c': 280 { 281 int warn2 = IN_SOME; 282 283 pt = _fmt(locale->c_fmt, t, pt, ptlim, warnp, locale); 284 if (warn2 == IN_ALL) 285 warn2 = IN_THIS; 286 if (warn2 > *warnp) 287 *warnp = warn2; 288 } 289 continue; 290 case 'D': 291 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, locale); 292 continue; 293 case 'd': 294 pt = _conv(t->tm_mday, 295 getformat(modifier, "%02d", 296 "%2d", "%d", "%02d"), 297 pt, ptlim); 298 continue; 299 case 'E': 300 case 'O': 301 /* 302 ** C99 locale modifiers. 303 ** The sequences 304 ** %Ec %EC %Ex %EX %Ey %EY 305 ** %Od %oe %OH %OI %Om %OM 306 ** %OS %Ou %OU %OV %Ow %OW %Oy 307 ** are supposed to provide alternate 308 ** representations. 309 */ 310 goto label; 311 case '_': 312 case '-': 313 case '0': 314 case '^': 315 case '#': 316 modifier = *format; 317 goto label; 318 case 'e': 319 pt = _conv(t->tm_mday, 320 getformat(modifier, "%2d", 321 "%2d", "%d", "%02d"), 322 pt, ptlim); 323 continue; 324 case 'F': 325 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, locale); 326 continue; 327 case 'H': 328 pt = _conv(t->tm_hour, 329 getformat(modifier, "%02d", 330 "%2d", "%d", "%02d"), 331 pt, ptlim); 332 continue; 333 case 'I': 334 pt = _conv((t->tm_hour % 12) ? 335 (t->tm_hour % 12) : 12, 336 getformat(modifier, "%02d", 337 "%2d", "%d", "%02d"), 338 pt, ptlim); 339 continue; 340 case 'j': 341 pt = _conv(t->tm_yday + 1, 342 getformat(modifier, "%03d", "%3d", "%d", "%03d"), 343 pt, ptlim); 344 continue; 345 case 'k': 346 /* 347 ** This used to be... 348 ** _conv(t->tm_hour % 12 ? 349 ** t->tm_hour % 12 : 12, 2, ' '); 350 ** ...and has been changed to the below to 351 ** match SunOS 4.1.1 and Arnold Robbins' 352 ** strftime version 3.0. That is, "%k" and 353 ** "%l" have been swapped. 354 ** (ado, 1993-05-24) 355 */ 356 pt = _conv(t->tm_hour, 357 getformat(modifier, "%2d", 358 "%2d", "%d", "%02d"), 359 pt, ptlim); 360 continue; 361#ifdef KITCHEN_SINK 362 case 'K': 363 /* 364 ** After all this time, still unclaimed! 365 */ 366 pt = _add("kitchen sink", pt, ptlim, modifier); 367 continue; 368#endif /* defined KITCHEN_SINK */ 369 case 'l': 370 /* 371 ** This used to be... 372 ** _conv(t->tm_hour, 2, ' '); 373 ** ...and has been changed to the below to 374 ** match SunOS 4.1.1 and Arnold Robbin's 375 ** strftime version 3.0. That is, "%k" and 376 ** "%l" have been swapped. 377 ** (ado, 1993-05-24) 378 */ 379 pt = _conv((t->tm_hour % 12) ? 380 (t->tm_hour % 12) : 12, 381 getformat(modifier, "%2d", 382 "%2d", "%d", "%02d"), 383 pt, ptlim); 384 continue; 385 case 'M': 386 pt = _conv(t->tm_min, 387 getformat(modifier, "%02d", 388 "%2d", "%d", "%02d"), 389 pt, ptlim); 390 continue; 391 case 'm': 392 pt = _conv(t->tm_mon + 1, 393 getformat(modifier, "%02d", 394 "%2d", "%d", "%02d"), 395 pt, ptlim); 396 continue; 397 case 'n': 398 pt = _add("\n", pt, ptlim, modifier); 399 continue; 400 case 'p': 401 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? 402 locale->pm : 403 locale->am, 404 pt, ptlim, modifier); 405 continue; 406 case 'P': 407 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? 408 locale->pm : 409 locale->am, 410 pt, ptlim, FORCE_LOWER_CASE); 411 continue; 412 case 'R': 413 pt = _fmt("%H:%M", t, pt, ptlim, warnp, locale); 414 continue; 415 case 'r': 416 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, locale); 417 continue; 418 case 'S': 419 pt = _conv(t->tm_sec, 420 getformat(modifier, "%02d", 421 "%2d", "%d", "%02d"), 422 pt, ptlim); 423 continue; 424 case 's': 425 { 426 struct tm tm; 427 char buf[INT_STRLEN_MAXIMUM( 428 time64_t) + 1]; 429 time64_t mkt; 430 431 tm = *t; 432 mkt = mktime64(&tm); 433 if (TYPE_SIGNED(time64_t)) 434 (void) snprintf(buf, sizeof(buf), "%lld", 435 (long long) mkt); 436 else (void) snprintf(buf, sizeof(buf), "%llu", 437 (unsigned long long) mkt); 438 pt = _add(buf, pt, ptlim, modifier); 439 } 440 continue; 441 case 'T': 442 pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, locale); 443 continue; 444 case 't': 445 pt = _add("\t", pt, ptlim, modifier); 446 continue; 447 case 'U': 448 pt = _conv((t->tm_yday + DAYSPERWEEK - 449 t->tm_wday) / DAYSPERWEEK, 450 getformat(modifier, "%02d", 451 "%2d", "%d", "%02d"), 452 pt, ptlim); 453 continue; 454 case 'u': 455 /* 456 ** From Arnold Robbins' strftime version 3.0: 457 ** "ISO 8601: Weekday as a decimal number 458 ** [1 (Monday) - 7]" 459 ** (ado, 1993-05-24) 460 */ 461 pt = _conv((t->tm_wday == 0) ? 462 DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim); 463 continue; 464 case 'V': /* ISO 8601 week number */ 465 case 'G': /* ISO 8601 year (four digits) */ 466 case 'g': /* ISO 8601 year (two digits) */ 467/* 468** From Arnold Robbins' strftime version 3.0: "the week number of the 469** year (the first Monday as the first day of week 1) as a decimal number 470** (01-53)." 471** (ado, 1993-05-24) 472** 473** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn: 474** "Week 01 of a year is per definition the first week which has the 475** Thursday in this year, which is equivalent to the week which contains 476** the fourth day of January. In other words, the first week of a new year 477** is the week which has the majority of its days in the new year. Week 01 478** might also contain days from the previous year and the week before week 479** 01 of a year is the last week (52 or 53) of the previous year even if 480** it contains days from the new year. A week starts with Monday (day 1) 481** and ends with Sunday (day 7). For example, the first week of the year 482** 1997 lasts from 1996-12-30 to 1997-01-05..." 483** (ado, 1996-01-02) 484*/ 485 { 486 int year; 487 int base; 488 int yday; 489 int wday; 490 int w; 491 492 year = t->tm_year; 493 base = TM_YEAR_BASE; 494 yday = t->tm_yday; 495 wday = t->tm_wday; 496 for ( ; ; ) { 497 int len; 498 int bot; 499 int top; 500 501 len = isleap_sum(year, base) ? 502 DAYSPERLYEAR : 503 DAYSPERNYEAR; 504 /* 505 ** What yday (-3 ... 3) does 506 ** the ISO year begin on? 507 */ 508 bot = ((yday + 11 - wday) % 509 DAYSPERWEEK) - 3; 510 /* 511 ** What yday does the NEXT 512 ** ISO year begin on? 513 */ 514 top = bot - 515 (len % DAYSPERWEEK); 516 if (top < -3) 517 top += DAYSPERWEEK; 518 top += len; 519 if (yday >= top) { 520 ++base; 521 w = 1; 522 break; 523 } 524 if (yday >= bot) { 525 w = 1 + ((yday - bot) / 526 DAYSPERWEEK); 527 break; 528 } 529 --base; 530 yday += isleap_sum(year, base) ? 531 DAYSPERLYEAR : 532 DAYSPERNYEAR; 533 } 534#ifdef XPG4_1994_04_09 535 if ((w == 52 && 536 t->tm_mon == TM_JANUARY) || 537 (w == 1 && 538 t->tm_mon == TM_DECEMBER)) 539 w = 53; 540#endif /* defined XPG4_1994_04_09 */ 541 if (*format == 'V') 542 pt = _conv(w, 543 getformat(modifier, 544 "%02d", 545 "%2d", 546 "%d", 547 "%02d"), 548 pt, ptlim); 549 else if (*format == 'g') { 550 *warnp = IN_ALL; 551 pt = _yconv(year, base, 0, 1, 552 pt, ptlim, modifier); 553 } else pt = _yconv(year, base, 1, 1, 554 pt, ptlim, modifier); 555 } 556 continue; 557 case 'v': 558 /* 559 ** From Arnold Robbins' strftime version 3.0: 560 ** "date as dd-bbb-YYYY" 561 ** (ado, 1993-05-24) 562 */ 563 pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, locale); 564 continue; 565 case 'W': 566 pt = _conv((t->tm_yday + DAYSPERWEEK - 567 (t->tm_wday ? 568 (t->tm_wday - 1) : 569 (DAYSPERWEEK - 1))) / DAYSPERWEEK, 570 getformat(modifier, "%02d", 571 "%2d", "%d", "%02d"), 572 pt, ptlim); 573 continue; 574 case 'w': 575 pt = _conv(t->tm_wday, "%d", pt, ptlim); 576 continue; 577 case 'X': 578 pt = _fmt(locale->X_fmt, t, pt, ptlim, warnp, locale); 579 continue; 580 case 'x': 581 { 582 int warn2 = IN_SOME; 583 584 pt = _fmt(locale->x_fmt, t, pt, ptlim, &warn2, locale); 585 if (warn2 == IN_ALL) 586 warn2 = IN_THIS; 587 if (warn2 > *warnp) 588 *warnp = warn2; 589 } 590 continue; 591 case 'y': 592 *warnp = IN_ALL; 593 pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1, 594 pt, ptlim, modifier); 595 continue; 596 case 'Y': 597 pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1, 598 pt, ptlim, modifier); 599 continue; 600 case 'Z': 601#ifdef TM_ZONE 602 if (t->TM_ZONE != NULL) 603 pt = _add(t->TM_ZONE, pt, ptlim, 604 modifier); 605 else 606#endif /* defined TM_ZONE */ 607 if (t->tm_isdst >= 0) 608 pt = _add(tzname[t->tm_isdst != 0], 609 pt, ptlim, modifier); 610 /* 611 ** C99 says that %Z must be replaced by the 612 ** empty string if the time zone is not 613 ** determinable. 614 */ 615 continue; 616 case 'z': 617 { 618 long diff; 619 char const * sign; 620 621 if (t->tm_isdst < 0) 622 continue; 623#ifdef TM_GMTOFF 624 diff = t->TM_GMTOFF; 625#else /* !defined TM_GMTOFF */ 626 /* 627 ** C99 says that the UT offset must 628 ** be computed by looking only at 629 ** tm_isdst. This requirement is 630 ** incorrect, since it means the code 631 ** must rely on magic (in this case 632 ** altzone and timezone), and the 633 ** magic might not have the correct 634 ** offset. Doing things correctly is 635 ** tricky and requires disobeying C99; 636 ** see GNU C strftime for details. 637 ** For now, punt and conform to the 638 ** standard, even though it's incorrect. 639 ** 640 ** C99 says that %z must be replaced by the 641 ** empty string if the time zone is not 642 ** determinable, so output nothing if the 643 ** appropriate variables are not available. 644 */ 645 if (t->tm_isdst == 0) 646#ifdef USG_COMPAT 647 diff = -timezone; 648#else /* !defined USG_COMPAT */ 649 continue; 650#endif /* !defined USG_COMPAT */ 651 else 652#ifdef ALTZONE 653 diff = -altzone; 654#else /* !defined ALTZONE */ 655 continue; 656#endif /* !defined ALTZONE */ 657#endif /* !defined TM_GMTOFF */ 658 if (diff < 0) { 659 sign = "-"; 660 diff = -diff; 661 } else sign = "+"; 662 pt = _add(sign, pt, ptlim, modifier); 663 diff /= SECSPERMIN; 664 diff = (diff / MINSPERHOUR) * 100 + 665 (diff % MINSPERHOUR); 666 pt = _conv(diff, 667 getformat(modifier, "%04d", 668 "%4d", "%d", "%04d"), 669 pt, ptlim); 670 } 671 continue; 672 case '+': 673 pt = _fmt(locale->date_fmt, t, pt, ptlim, 674 warnp, locale); 675 continue; 676 case '%': 677 /* 678 ** X311J/88-090 (4.12.3.5): if conversion char is 679 ** undefined, behavior is undefined. Print out the 680 ** character itself as printf(3) also does. 681 */ 682 default: 683 break; 684 } 685 } 686 if (pt == ptlim) 687 break; 688 *pt++ = *format; 689 } 690 return pt; 691} 692 693static char * 694_conv(n, format, pt, ptlim) 695const int n; 696const char * const format; 697char * const pt; 698const char * const ptlim; 699{ 700 char buf[INT_STRLEN_MAXIMUM(int) + 1]; 701 702 (void) snprintf(buf, sizeof(buf), format, n); 703 return _add(buf, pt, ptlim, 0); 704} 705 706static char * 707_add(str, pt, ptlim, modifier) 708const char * str; 709char * pt; 710const char * const ptlim; 711int modifier; 712{ 713 int c; 714 715 switch (modifier) { 716 case FORCE_LOWER_CASE: 717 while (pt < ptlim && (*pt = tolower(*str++)) != '\0') { 718 ++pt; 719 } 720 break; 721 722 case '^': 723 while (pt < ptlim && (*pt = toupper(*str++)) != '\0') { 724 ++pt; 725 } 726 break; 727 728 case '#': 729 while (pt < ptlim && (c = *str++) != '\0') { 730 if (isupper(c)) { 731 c = tolower(c); 732 } else if (islower(c)) { 733 c = toupper(c); 734 } 735 *pt = c; 736 ++pt; 737 } 738 739 break; 740 741 default: 742 while (pt < ptlim && (*pt = *str++) != '\0') { 743 ++pt; 744 } 745 } 746 747 return pt; 748} 749 750/* 751** POSIX and the C Standard are unclear or inconsistent about 752** what %C and %y do if the year is negative or exceeds 9999. 753** Use the convention that %C concatenated with %y yields the 754** same output as %Y, and that %Y contains at least 4 bytes, 755** with more only if necessary. 756*/ 757 758static char * 759_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier) 760const int a; 761const int b; 762const int convert_top; 763const int convert_yy; 764char * pt; 765const char * const ptlim; 766int modifier; 767{ 768 register int lead; 769 register int trail; 770 771#define DIVISOR 100 772 trail = a % DIVISOR + b % DIVISOR; 773 lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR; 774 trail %= DIVISOR; 775 if (trail < 0 && lead > 0) { 776 trail += DIVISOR; 777 --lead; 778 } else if (lead < 0 && trail > 0) { 779 trail -= DIVISOR; 780 ++lead; 781 } 782 if (convert_top) { 783 if (lead == 0 && trail < 0) 784 pt = _add("-0", pt, ptlim, modifier); 785 else pt = _conv(lead, getformat(modifier, "%02d", 786 "%2d", "%d", "%02d"), 787 pt, ptlim); 788 } 789 if (convert_yy) 790 pt = _conv(((trail < 0) ? -trail : trail), 791 getformat(modifier, "%02d", "%2d", "%d", "%02d"), 792 pt, ptlim); 793 return pt; 794} 795