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