update from main archive 960919
[glibc.git] / time / strftime.c
blob7837373aed657707f3d70e125e65a6033336cb69
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #ifdef _LIBC
24 # define HAVE_LIMITS_H 1
25 # define HAVE_MBLEN 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_TM_GMTOFF 1
28 # define HAVE_TM_ZONE 1
29 # define MULTIBYTE_IS_FORMAT_SAFE 1
30 # define STDC_HEADERS 1
31 # include <ansidecl.h>
32 # include "../locale/localeinfo.h"
33 #endif
35 #include <sys/types.h> /* Some systems define `time_t' here. */
37 #ifdef TIME_WITH_SYS_TIME
38 # include <sys/time.h>
39 # include <time.h>
40 #else
41 # ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
43 # else
44 # include <time.h>
45 # endif
46 #endif
48 /* Do multibyte processing if multibytes are supported, unless
49 multibyte sequences are safe in formats. Multibyte sequences are
50 safe if they cannot contain byte sequences that look like format
51 conversion specifications. The GNU C Library uses UTF8 multibyte
52 encoding, which is safe for formats, but strftime.c can be used
53 with other C libraries that use unsafe encodings. */
54 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
56 #if DO_MULTIBYTE
57 # if HAVE_MBRLEN
58 # include <wchar.h>
59 # else
60 /* Simulate mbrlen with mblen as best we can. */
61 # define mbstate_t int
62 # define mbrlen(s, n, ps) mblen (s, n)
63 # define mbsinit(ps) (*(ps) == 0)
64 # endif
65 static const mbstate_t mbstate_zero;
66 #endif
68 #if HAVE_LIMITS_H
69 # include <limits.h>
70 #endif
72 #if STDC_HEADERS
73 # include <stddef.h>
74 # include <stdlib.h>
75 # include <string.h>
76 #else
77 # define memcpy(d, s, n) bcopy (s, d, n)
78 #endif
80 #ifndef __P
81 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
82 #define __P(args) args
83 #else
84 #define __P(args) ()
85 #endif /* GCC. */
86 #endif /* Not __P. */
88 #ifndef PTR
89 #ifdef __STDC__
90 #define PTR void *
91 #else
92 #define PTR char *
93 #endif
94 #endif
96 #ifndef CHAR_BIT
97 #define CHAR_BIT 8
98 #endif
100 #define TYPE_SIGNED(t) ((t) -1 < 0)
102 /* Bound on length of the string representing an integer value of type t.
103 Subtract one for the sign bit if t is signed;
104 302 / 1000 is log10 (2) rounded up;
105 add one for integer division truncation;
106 add one more for a minus sign if t is signed. */
107 #define INT_STRLEN_BOUND(t) \
108 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
110 #define TM_YEAR_BASE 1900
112 #ifndef __isleap
113 /* Nonzero if YEAR is a leap year (every 4 years,
114 except every 100th isn't, and every 400th is). */
115 #define __isleap(year) \
116 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
117 #endif
120 #ifdef _LIBC
121 # define gmtime_r __gmtime_r
122 # define localtime_r __localtime_r
123 #else
124 # if ! HAVE_LOCALTIME_R
125 # if ! HAVE_TM_GMTOFF
126 /* Approximate gmtime_r as best we can in its absence. */
127 #define gmtime_r my_gmtime_r
128 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
129 static struct tm *
130 gmtime_r (t, tp)
131 const time_t *t;
132 struct tm *tp;
134 struct tm *l = gmtime (t);
135 if (! l)
136 return 0;
137 *tp = *l;
138 return tp;
140 # endif /* ! HAVE_TM_GMTOFF */
142 /* Approximate localtime_r as best we can in its absence. */
143 #define localtime_r my_localtime_r
144 static struct tm *localtime_r __P ((const time_t *, struct tm *));
145 static struct tm *
146 localtime_r (t, tp)
147 const time_t *t;
148 struct tm *tp;
150 struct tm *l = localtime (t);
151 if (! l)
152 return 0;
153 *tp = *l;
154 return tp;
156 # endif /* ! HAVE_LOCALTIME_R */
157 #endif /* ! defined (_LIBC) */
160 #define add(n, f) \
161 do \
163 i += (n); \
164 if (i >= maxsize) \
165 return 0; \
166 else \
167 if (p) \
169 f; \
170 p += (n); \
172 } while (0)
173 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
175 #if ! HAVE_TM_GMTOFF
176 /* Yield the difference between *A and *B,
177 measured in seconds, ignoring leap seconds. */
178 static int tm_diff __P ((const struct tm *, const struct tm *));
179 static int
180 tm_diff (a, b)
181 const struct tm *a;
182 const struct tm *b;
184 /* Compute intervening leap days correctly even if year is negative.
185 Take care to avoid int overflow in leap day calculations,
186 but it's OK to assume that A and B are close to each other. */
187 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
188 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
189 int a100 = a4 / 25 - (a4 % 25 < 0);
190 int b100 = b4 / 25 - (b4 % 25 < 0);
191 int a400 = a100 >> 2;
192 int b400 = b100 >> 2;
193 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
194 int years = a->tm_year - b->tm_year;
195 int days = (365 * years + intervening_leap_days
196 + (a->tm_yday - b->tm_yday));
197 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
198 + (a->tm_min - b->tm_min))
199 + (a->tm_sec - b->tm_sec));
201 #endif /* ! HAVE_TM_GMTOFF */
205 /* The number of days from the first day of the first ISO week of this
206 year to the year day YDAY with week day WDAY. ISO weeks start on
207 Monday; the first ISO week has the year's first Thursday. YDAY may
208 be as small as YDAY_MINIMUM. */
209 #define ISO_WEEK_START_WDAY 1 /* Monday */
210 #define ISO_WEEK1_WDAY 4 /* Thursday */
211 #define YDAY_MINIMUM (-366)
212 static int iso_week_days __P ((int, int));
213 #ifdef __GNUC__
214 inline
215 #endif
216 static int
217 iso_week_days (yday, wday)
218 int yday;
219 int wday;
221 /* Add enough to the first operand of % to make it nonnegative. */
222 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
223 return (yday
224 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
225 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
229 #ifndef _NL_CURRENT
230 static char const weekday_name[][10] =
232 "Sunday", "Monday", "Tuesday", "Wednesday",
233 "Thursday", "Friday", "Saturday"
235 static char const month_name[][10] =
237 "January", "February", "March", "April", "May", "June",
238 "July", "August", "September", "October", "November", "December"
240 #endif
242 /* Write information from TP into S according to the format
243 string FORMAT, writing no more that MAXSIZE characters
244 (including the terminating '\0') and returning number of
245 characters written. If S is NULL, nothing will be written
246 anywhere, so to determine how many characters would be
247 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
248 size_t
249 strftime (s, maxsize, format, tp)
250 char *s;
251 size_t maxsize;
252 const char *format;
253 register const struct tm *tp;
255 int hour12 = tp->tm_hour;
256 #ifdef _NL_CURRENT
257 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
258 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
259 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
260 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
261 const char *const ampm = _NL_CURRENT (LC_TIME,
262 hour12 > 11 ? PM_STR : AM_STR);
263 size_t aw_len = strlen(a_wkday);
264 size_t am_len = strlen(a_month);
265 size_t ap_len = strlen (ampm);
267 const char *alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS);
268 const char *end_alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS + 1);
269 #else
270 const char *const f_wkday = weekday_name[tp->tm_wday];
271 const char *const f_month = month_name[tp->tm_mon];
272 const char *const a_wkday = f_wkday;
273 const char *const a_month = f_month;
274 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
275 size_t aw_len = 3;
276 size_t am_len = 3;
277 size_t ap_len = 2;
278 #endif
279 size_t wkday_len = strlen (f_wkday);
280 size_t month_len = strlen (f_month);
281 const char *zone;
282 size_t zonelen;
283 register size_t i = 0;
284 register char *p = s;
285 register const char *f;
287 zone = 0;
288 #if HAVE_TM_ZONE
289 zone = (const char *) tp->tm_zone;
290 #endif
291 #if HAVE_TZNAME
292 if (!(zone && *zone) && tp->tm_isdst >= 0)
293 zone = tzname[tp->tm_isdst];
294 #endif
295 if (! zone)
296 zone = ""; /* POSIX.2 requires the empty string here. */
298 zonelen = strlen (zone);
300 if (hour12 > 12)
301 hour12 -= 12;
302 else
303 if (hour12 == 0) hour12 = 12;
305 for (f = format; *f != '\0'; ++f)
307 int pad; /* Padding for number ('-', '_', or 0). */
308 int modifier; /* Field modifier ('E', 'O', or 0). */
309 int digits; /* Max digits for numeric format. */
310 int number_value; /* Numeric value to be printed. */
311 int negative_number; /* 1 if the number is negative. */
312 const char *subfmt;
313 char *bufp;
314 char buf[1 + (sizeof (int) < sizeof (time_t)
315 ? INT_STRLEN_BOUND (time_t)
316 : INT_STRLEN_BOUND (int))];
318 #if DO_MULTIBYTE
320 switch (*f)
322 case '%':
323 break;
325 case '\a': case '\b': case '\t': case '\n':
326 case '\v': case '\f': case '\r':
327 case ' ': case '!': case '"': case '#': case '&': case'\'':
328 case '(': case ')': case '*': case '+': case ',': case '-':
329 case '.': case '/': case '0': case '1': case '2': case '3':
330 case '4': case '5': case '6': case '7': case '8': case '9':
331 case ':': case ';': case '<': case '=': case '>': case '?':
332 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
333 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
334 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
335 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
336 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
337 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
338 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
339 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
340 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
341 case 'x': case 'y': case 'z': case '{': case '|': case '}':
342 case '~':
343 /* The C Standard requires these 98 characters (plus '%') to
344 be in the basic execution character set. None of these
345 characters can start a multibyte sequence, so they need
346 not be analyzed further. */
347 add (1, *p = *f);
348 continue;
350 default:
351 /* Copy this multibyte sequence until we reach its end, find
352 an error, or come back to the initial shift state. */
354 mbstate_t mbstate = mbstate_zero;
355 size_t len = 0;
359 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
361 if (bytes == 0)
362 break;
364 if (bytes == (size_t) -2 || bytes == (size_t) -1)
366 len++;
367 break;
370 len += bytes;
372 while (! mbsinit (&mbstate));
374 cpy (len, f);
375 continue;
379 #else /* ! DO_MULTIBYTE */
381 /* Either multibyte encodings are not supported, or they are
382 safe for formats, so any non-'%' byte can be copied through. */
383 if (*f != '%')
385 add (1, *p = *f);
386 continue;
389 #endif /* ! DO_MULTIBYTE */
391 /* Check for flags that can modify a number format. */
392 ++f;
393 switch (*f)
395 case '_':
396 case '-':
397 pad = *f++;
398 break;
400 default:
401 pad = 0;
402 break;
405 /* Check for modifiers. */
406 switch (*f)
408 case 'E':
409 case 'O':
410 modifier = *f++;
411 break;
413 default:
414 modifier = 0;
415 break;
418 /* Now do the specified format. */
419 switch (*f)
421 #define DO_NUMBER(d, v) \
422 digits = d; number_value = v; goto do_number
423 #define DO_NUMBER_SPACEPAD(d, v) \
424 digits = d; number_value = v; goto do_number_spacepad
426 case '\0': /* GNU extension: % at end of format. */
427 --f;
428 /* Fall through. */
429 case '%':
430 if (modifier != 0)
431 goto bad_format;
432 add (1, *p = *f);
433 break;
435 case 'a':
436 if (modifier != 0)
437 goto bad_format;
438 cpy (aw_len, a_wkday);
439 break;
441 case 'A':
442 if (modifier != 0)
443 goto bad_format;
444 cpy (wkday_len, f_wkday);
445 break;
447 case 'b':
448 case 'h': /* POSIX.2 extension. */
449 if (modifier != 0)
450 goto bad_format;
451 cpy (am_len, a_month);
452 break;
454 case 'B':
455 if (modifier != 0)
456 goto bad_format;
457 cpy (month_len, f_month);
458 break;
460 case 'c':
461 if (modifier == 'O')
462 goto bad_format;
463 #ifdef _NL_CURRENT
464 if (! (modifier == 'E'
465 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
466 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
467 #else
468 subfmt = "%a %b %e %H:%M:%S %Z %Y";
469 #endif
471 subformat:
473 size_t len = strftime (p, maxsize - i, subfmt, tp);
474 if (len == 0 && *subfmt)
475 return 0;
476 add (len, ;);
478 break;
480 case 'C': /* POSIX.2 extension. */
481 if (modifier == 'O')
482 goto bad_format;
483 #ifdef _NL_CURRENT
484 /* XXX %EC is not implemented yet. */
485 #endif
487 int year = tp->tm_year + TM_YEAR_BASE;
488 DO_NUMBER (1, year / 100 - (year % 100 < 0));
491 case 'x':
492 if (modifier == 'O')
493 goto bad_format;
494 #ifdef _NL_CURRENT
495 if (! (modifier == 'E'
496 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
497 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
498 goto subformat;
499 #endif
500 /* Fall through. */
501 case 'D': /* POSIX.2 extension. */
502 if (modifier != 0)
503 goto bad_format;
504 subfmt = "%m/%d/%y";
505 goto subformat;
507 case 'd':
508 if (modifier == 'E')
509 goto bad_format;
511 DO_NUMBER (2, tp->tm_mday);
513 case 'e': /* POSIX.2 extension. */
514 if (modifier == 'E')
515 goto bad_format;
517 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
519 /* All numeric formats set DIGITS and NUMBER_VALUE and then
520 jump to one of these two labels. */
522 do_number_spacepad:
523 /* Force `_' flag. */
524 pad = '_';
526 do_number:
527 /* Format the number according to the MODIFIER flag. */
529 #ifdef _NL_CURRENT
530 if (modifier == 'O' && 0 <= number_value)
532 /* ALT_DIGITS is the first entry in an array with
533 alternative digit symbols. We have to find string
534 number NUMBER_VALUE, but must not look beyond
535 END_ALT_DIGITS. */
536 int run = number_value;
537 const char *cp = alt_digits;
539 while (run-- > 0 && cp < end_alt_digits)
540 cp = strchr (cp, '\0') + 1;
542 if (cp < end_alt_digits)
544 size_t digitlen = strlen (cp);
545 if (digitlen != 0)
547 cpy (digitlen, cp);
548 break;
552 #endif
554 unsigned int u = number_value;
556 bufp = buf + sizeof (buf);
557 negative_number = number_value < 0;
559 if (negative_number)
560 u = -u;
563 *--bufp = u % 10 + '0';
564 while ((u /= 10) != 0);
567 do_number_sign_and_padding:
568 if (negative_number)
569 *--bufp = '-';
571 if (pad != '-')
573 int padding = digits - (buf + sizeof (buf) - bufp);
575 if (pad == '_')
577 while (0 < padding--)
578 *--bufp = ' ';
580 else
582 bufp += negative_number;
583 while (0 < padding--)
584 *--bufp = '0';
585 if (negative_number)
586 *--bufp = '-';
590 cpy (buf + sizeof (buf) - bufp, bufp);
591 break;
594 case 'H':
595 if (modifier == 'E')
596 goto bad_format;
598 DO_NUMBER (2, tp->tm_hour);
600 case 'I':
601 if (modifier == 'E')
602 goto bad_format;
604 DO_NUMBER (2, hour12);
606 case 'k': /* GNU extension. */
607 if (modifier == 'E')
608 goto bad_format;
610 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
612 case 'l': /* GNU extension. */
613 if (modifier == 'E')
614 goto bad_format;
616 DO_NUMBER_SPACEPAD (2, hour12);
618 case 'j':
619 if (modifier == 'E')
620 goto bad_format;
622 DO_NUMBER (3, 1 + tp->tm_yday);
624 case 'M':
625 if (modifier == 'E')
626 goto bad_format;
628 DO_NUMBER (2, tp->tm_min);
630 case 'm':
631 if (modifier == 'E')
632 goto bad_format;
634 DO_NUMBER (2, tp->tm_mon + 1);
636 case 'n': /* POSIX.2 extension. */
637 add (1, *p = '\n');
638 break;
640 case 'p':
641 cpy (ap_len, ampm);
642 break;
644 case 'R': /* GNU extension. */
645 subfmt = "%H:%M";
646 goto subformat;
648 case 'r': /* POSIX.2 extension. */
649 #ifdef _NL_CURRENT
650 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
651 #endif
652 subfmt = "%I:%M:%S %p";
653 goto subformat;
655 case 'S':
656 if (modifier == 'E')
657 goto bad_format;
659 DO_NUMBER (2, tp->tm_sec);
661 case 's': /* GNU extension. */
663 struct tm ltm = *tp;
664 time_t t = mktime (&ltm);
666 /* Generate string value for T using time_t arithmetic;
667 this works even if sizeof (long) < sizeof (time_t). */
669 bufp = buf + sizeof (buf);
670 negative_number = t < 0;
674 int d = t % 10;
675 t /= 10;
677 if (negative_number)
679 d = -d;
681 /* Adjust if division truncates to minus infinity. */
682 if (0 < -1 % 10 && d < 0)
684 t++;
685 d += 10;
689 *--bufp = d + '0';
691 while (t != 0);
693 digits = 1;
694 goto do_number_sign_and_padding;
697 case 'X':
698 if (modifier == 'O')
699 goto bad_format;
700 #ifdef _NL_CURRENT
701 if (! (modifier == 'E'
702 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
703 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
704 goto subformat;
705 #endif
706 /* Fall through. */
707 case 'T': /* POSIX.2 extension. */
708 subfmt = "%H:%M:%S";
709 goto subformat;
711 case 't': /* POSIX.2 extension. */
712 add (1, *p = '\t');
713 break;
715 case 'u': /* POSIX.2 extension. */
716 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
718 case 'U':
719 if (modifier == 'E')
720 goto bad_format;
722 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
724 case 'V':
725 case 'g': /* GNU extension. */
726 case 'G': /* GNU extension. */
727 if (modifier == 'E')
728 goto bad_format;
730 int year = tp->tm_year + TM_YEAR_BASE;
731 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
733 if (days < 0)
735 /* This ISO week belongs to the previous year. */
736 year--;
737 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
738 tp->tm_wday);
740 else
742 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
743 tp->tm_wday);
744 if (0 <= d)
746 /* This ISO week belongs to the next year. */
747 year++;
748 days = d;
752 switch (*f)
754 case 'g':
755 DO_NUMBER (2, (year % 100 + 100) % 100);
757 case 'G':
758 DO_NUMBER (1, year);
760 default:
761 DO_NUMBER (2, days / 7 + 1);
765 case 'W':
766 if (modifier == 'E')
767 goto bad_format;
769 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
771 case 'w':
772 if (modifier == 'E')
773 goto bad_format;
775 DO_NUMBER (1, tp->tm_wday);
777 case 'Y':
778 #ifdef _NL_CURRENT
779 if (modifier == 'E'
780 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_YEAR)) != '\0')
781 goto subformat;
782 #endif
783 if (modifier == 'O')
784 goto bad_format;
785 else
786 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
788 case 'y':
789 #ifdef _NL_CURRENT
790 /* XXX %Ey is not implemented yet. */
791 #endif
792 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
794 case 'Z':
795 cpy(zonelen, zone);
796 break;
798 case 'z': /* GNU extension. */
799 if (tp->tm_isdst < 0)
800 break;
803 int diff;
804 #if HAVE_TM_GMTOFF
805 diff = tp->tm_gmtoff;
806 #else
807 struct tm gtm;
808 struct tm ltm = *tp;
809 time_t lt = mktime (&ltm);
811 if (lt == (time_t) -1)
813 /* mktime returns -1 for errors, but -1 is also a
814 valid time_t value. Check whether an error really
815 occurred. */
816 struct tm tm;
817 localtime_r (&lt, &tm);
819 if ((ltm.tm_sec ^ tm.tm_sec)
820 | (ltm.tm_min ^ tm.tm_min)
821 | (ltm.tm_hour ^ tm.tm_hour)
822 | (ltm.tm_mday ^ tm.tm_mday)
823 | (ltm.tm_mon ^ tm.tm_mon)
824 | (ltm.tm_year ^ tm.tm_year))
825 break;
828 if (! gmtime_r (&lt, &gtm))
829 break;
831 diff = tm_diff (&ltm, &gtm);
832 #endif
834 if (diff < 0)
836 add (1, *p = '-');
837 diff = -diff;
839 else
840 add (1, *p = '+');
842 diff /= 60;
843 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
846 default:
847 /* Unknown format; output the format, including the '%',
848 since this is most likely the right thing to do if a
849 multibyte string has been misparsed. */
850 bad_format:
852 int flen;
853 for (flen = 2; f[1 - flen] != '%'; flen++)
854 continue;
855 cpy (flen, &f[1 - flen]);
857 break;
861 if (p)
862 *p = '\0';
863 return i;