1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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 not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
24 # define HAVE_LIMITS_H 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_TM_GMTOFF 1
29 # define HAVE_TM_ZONE 1
30 # define HAVE_TZNAME 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include "../locale/localeinfo.h"
37 #if defined emacs && !defined HAVE_BCOPY
38 # define HAVE_MEMCPY 1
42 #include <sys/types.h> /* Some systems define `time_t' here. */
44 #ifdef TIME_WITH_SYS_TIME
45 # include <sys/time.h>
48 # ifdef HAVE_SYS_TIME_H
49 # include <sys/time.h>
55 extern char *tzname
[];
58 /* Do multibyte processing if multibytes are supported, unless
59 multibyte sequences are safe in formats. Multibyte sequences are
60 safe if they cannot contain byte sequences that look like format
61 conversion specifications. The GNU C Library uses UTF8 multibyte
62 encoding, which is safe for formats, but strftime.c can be used
63 with other C libraries that use unsafe encodings. */
64 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
70 /* Simulate mbrlen with mblen as best we can. */
71 # define mbstate_t int
72 # define mbrlen(s, n, ps) mblen (s, n)
73 # define mbsinit(ps) (*(ps) == 0)
75 static const mbstate_t mbstate_zero
;
88 # define memcpy(d, s, n) bcopy ((s), (d), (n))
93 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
94 # define __P(args) args
116 #define TYPE_SIGNED(t) ((t) -1 < 0)
118 /* Bound on length of the string representing an integer value of type t.
119 Subtract one for the sign bit if t is signed;
120 302 / 1000 is log10 (2) rounded up;
121 add one for integer division truncation;
122 add one more for a minus sign if t is signed. */
123 #define INT_STRLEN_BOUND(t) \
124 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
126 #define TM_YEAR_BASE 1900
129 /* Nonzero if YEAR is a leap year (every 4 years,
130 except every 100th isn't, and every 400th is). */
131 # define __isleap(year) \
132 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
137 # define gmtime_r __gmtime_r
138 # define localtime_r __localtime_r
139 # define tzname __tzname
140 # define tzset __tzset
142 # if ! HAVE_LOCALTIME_R
143 # if ! HAVE_TM_GMTOFF
144 /* Approximate gmtime_r as best we can in its absence. */
146 # define gmtime_r my_gmtime_r
147 static struct tm
*gmtime_r
__P ((const time_t *, struct tm
*));
153 struct tm
*l
= gmtime (t
);
159 # endif /* ! HAVE_TM_GMTOFF */
161 /* Approximate localtime_r as best we can in its absence. */
163 # define localtime_r my_ftime_localtime_r
164 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
170 struct tm
*l
= localtime (t
);
176 # endif /* ! HAVE_LOCALTIME_R */
177 #endif /* ! defined (_LIBC) */
180 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
181 /* Some systems lack the `memset' function and we don't want to
182 introduce additional dependencies. */
183 /* The SGI compiler reportedly barfs on the trailing null
184 if we use a string constant as the initializer. 28 June 1997, rms. */
185 static const char spaces
[16] = /* " " */
186 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
187 static const char zeroes
[16] = /* "0000000000000000" */
188 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
190 # define memset_space(P, Len) \
196 int _this = _len > 16 ? 16 : _len; \
197 memcpy ((P), spaces, _this); \
204 # define memset_zero(P, Len) \
210 int _this = _len > 16 ? 16 : _len; \
211 memcpy ((P), zeroes, _this); \
218 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
219 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
226 int _delta = width - _n; \
227 int _incr = _n + (_delta > 0 ? _delta : 0); \
228 if (i + _incr >= maxsize) \
235 memset_zero (p, _delta); \
237 memset_space (p, _delta); \
248 memcpy_lowcase (p, (s), _n); \
249 else if (to_uppcase) \
250 memcpy_uppcase (p, (s), _n); \
252 memcpy ((PTR) p, (PTR) (s), _n))
257 # define TOUPPER(Ch) toupper (Ch)
258 # define TOLOWER(Ch) tolower (Ch)
260 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
261 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
263 /* We don't use `isdigit' here since the locale dependent
264 interpretation is not what we want here. We only need to accept
265 the arabic digits in the ASCII range. One day there is perhaps a
266 more reliable way to accept other sets of digits. */
267 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
269 static char *memcpy_lowcase
__P ((char *dest
, const char *src
, size_t len
));
272 memcpy_lowcase (dest
, src
, len
)
278 dest
[len
] = TOLOWER ((unsigned char) src
[len
]);
282 static char *memcpy_uppcase
__P ((char *dest
, const char *src
, size_t len
));
285 memcpy_uppcase (dest
, src
, len
)
291 dest
[len
] = TOUPPER ((unsigned char) src
[len
]);
297 /* Yield the difference between *A and *B,
298 measured in seconds, ignoring leap seconds. */
299 # define tm_diff ftime_tm_diff
300 static int tm_diff
__P ((const struct tm
*, const struct tm
*));
306 /* Compute intervening leap days correctly even if year is negative.
307 Take care to avoid int overflow in leap day calculations,
308 but it's OK to assume that A and B are close to each other. */
309 int a4
= (a
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (a
->tm_year
& 3);
310 int b4
= (b
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (b
->tm_year
& 3);
311 int a100
= a4
/ 25 - (a4
% 25 < 0);
312 int b100
= b4
/ 25 - (b4
% 25 < 0);
313 int a400
= a100
>> 2;
314 int b400
= b100
>> 2;
315 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
316 int years
= a
->tm_year
- b
->tm_year
;
317 int days
= (365 * years
+ intervening_leap_days
318 + (a
->tm_yday
- b
->tm_yday
));
319 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
320 + (a
->tm_min
- b
->tm_min
))
321 + (a
->tm_sec
- b
->tm_sec
));
323 #endif /* ! HAVE_TM_GMTOFF */
327 /* The number of days from the first day of the first ISO week of this
328 year to the year day YDAY with week day WDAY. ISO weeks start on
329 Monday; the first ISO week has the year's first Thursday. YDAY may
330 be as small as YDAY_MINIMUM. */
331 #define ISO_WEEK_START_WDAY 1 /* Monday */
332 #define ISO_WEEK1_WDAY 4 /* Thursday */
333 #define YDAY_MINIMUM (-366)
334 static int iso_week_days
__P ((int, int));
339 iso_week_days (yday
, wday
)
343 /* Add enough to the first operand of % to make it nonnegative. */
344 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
346 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
347 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
351 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
352 static char const weekday_name
[][10] =
354 "Sunday", "Monday", "Tuesday", "Wednesday",
355 "Thursday", "Friday", "Saturday"
357 static char const month_name
[][10] =
359 "January", "February", "March", "April", "May", "June",
360 "July", "August", "September", "October", "November", "December"
366 # define my_strftime emacs_strftime
367 /* Emacs 20.2 uses `-Dstrftime=emacs_strftime' when compiling,
368 because that's how strftime used to be configured.
369 Undo this, since it gets in the way of accessing the underlying strftime,
370 which is needed for things like %Ec in Solaris.
371 The following two lines can be removed once Emacs stops compiling with
372 `-Dstrftime=emacs_strftime'. */
374 size_t strftime
__P ((char *, size_t, const char *, const struct tm
*));
376 # define my_strftime strftime
379 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
380 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
381 Work around this bug by copying *tp before it might be munged. */
382 size_t _strftime_copytm
__P ((char *, size_t, const char *,
385 my_strftime (s
, maxsize
, format
, tp
)
393 return _strftime_copytm (s
, maxsize
, format
, &tmcopy
);
396 # define my_strftime(S, Maxsize, Format, Tp) \
397 _strftime_copytm (S, Maxsize, Format, Tp)
401 /* Write information from TP into S according to the format
402 string FORMAT, writing no more that MAXSIZE characters
403 (including the terminating '\0') and returning number of
404 characters written. If S is NULL, nothing will be written
405 anywhere, so to determine how many characters would be
406 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
408 my_strftime (s
, maxsize
, format
, tp
)
414 int hour12
= tp
->tm_hour
;
416 const char *const a_wkday
= _NL_CURRENT (LC_TIME
, ABDAY_1
+ tp
->tm_wday
);
417 const char *const f_wkday
= _NL_CURRENT (LC_TIME
, DAY_1
+ tp
->tm_wday
);
418 const char *const a_month
= _NL_CURRENT (LC_TIME
, ABMON_1
+ tp
->tm_mon
);
419 const char *const f_month
= _NL_CURRENT (LC_TIME
, MON_1
+ tp
->tm_mon
);
420 const char *const ampm
= _NL_CURRENT (LC_TIME
,
421 hour12
> 11 ? PM_STR
: AM_STR
);
422 size_t aw_len
= strlen (a_wkday
);
423 size_t am_len
= strlen (a_month
);
424 size_t ap_len
= strlen (ampm
);
427 const char *const f_wkday
= weekday_name
[tp
->tm_wday
];
428 const char *const f_month
= month_name
[tp
->tm_mon
];
429 const char *const a_wkday
= f_wkday
;
430 const char *const a_month
= f_month
;
431 const char *const ampm
= "AMPM" + 2 * (hour12
> 11);
437 #if defined _NL_CURRENT || !HAVE_STRFTIME
438 size_t wkday_len
= strlen (f_wkday
);
439 size_t month_len
= strlen (f_month
);
449 /* The POSIX test suite assumes that setting
450 the environment variable TZ to a new value before calling strftime()
451 will influence the result (the %Z format) even if the information in
452 TP is computed with a totally different time zone.
453 This is bogus: though POSIX allows bad behavior like this,
454 POSIX does not require it. Do the right thing instead. */
455 zone
= (const char *) tp
->tm_zone
;
458 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
459 time zone names contained in the external variable `tzname' shall
460 be set as if the tzset() function had been called. */
465 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
466 zone
= tzname
[tp
->tm_isdst
];
469 zone
= ""; /* POSIX.2 requires the empty string here. */
471 zonelen
= strlen (zone
);
476 if (hour12
== 0) hour12
= 12;
478 for (f
= format
; *f
!= '\0'; ++f
)
480 int pad
; /* Padding for number ('-', '_', or 0). */
481 int modifier
; /* Field modifier ('E', 'O', or 0). */
482 int digits
; /* Max digits for numeric format. */
483 int number_value
; /* Numeric value to be printed. */
484 int negative_number
; /* 1 if the number is negative. */
487 char buf
[1 + (sizeof (int) < sizeof (time_t)
488 ? INT_STRLEN_BOUND (time_t)
489 : INT_STRLEN_BOUND (int))];
503 case '\a': case '\b': case '\t': case '\n':
504 case '\v': case '\f': case '\r':
505 case ' ': case '!': case '"': case '#': case '&': case'\'':
506 case '(': case ')': case '*': case '+': case ',': case '-':
507 case '.': case '/': case '0': case '1': case '2': case '3':
508 case '4': case '5': case '6': case '7': case '8': case '9':
509 case ':': case ';': case '<': case '=': case '>': case '?':
510 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
511 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
512 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
513 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
514 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
515 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
516 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
517 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
518 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
519 case 'x': case 'y': case 'z': case '{': case '|': case '}':
521 /* The C Standard requires these 98 characters (plus '%') to
522 be in the basic execution character set. None of these
523 characters can start a multibyte sequence, so they need
524 not be analyzed further. */
529 /* Copy this multibyte sequence until we reach its end, find
530 an error, or come back to the initial shift state. */
532 mbstate_t mbstate
= mbstate_zero
;
537 size_t bytes
= mbrlen (f
+ len
, (size_t) -1, &mbstate
);
542 if (bytes
== (size_t) -2 || bytes
== (size_t) -1)
550 while (! mbsinit (&mbstate
));
557 #else /* ! DO_MULTIBYTE */
559 /* Either multibyte encodings are not supported, or they are
560 safe for formats, so any non-'%' byte can be copied through. */
567 #endif /* ! DO_MULTIBYTE */
569 /* Check for flags that can modify a format. */
575 /* This influences the number formats. */
582 /* This changes textual output. */
596 /* As a GNU extension we allow to specify the field width. */
606 while (ISDIGIT (*f
));
609 /* Check for modifiers. */
622 /* Now do the specified format. */
626 #define DO_NUMBER(d, v) \
627 digits = width == -1 ? d : width; \
628 number_value = v; goto do_number
629 #define DO_NUMBER_SPACEPAD(d, v) \
630 digits = width == -1 ? d : width; \
631 number_value = v; goto do_number_spacepad
647 #if defined _NL_CURRENT || !HAVE_STRFTIME
648 cpy (aw_len
, a_wkday
);
651 goto underlying_strftime
;
662 #if defined _NL_CURRENT || !HAVE_STRFTIME
663 cpy (wkday_len
, f_wkday
);
666 goto underlying_strftime
;
670 case 'h': /* POSIX.2 extension. */
673 #if defined _NL_CURRENT || !HAVE_STRFTIME
674 cpy (am_len
, a_month
);
677 goto underlying_strftime
;
688 #if defined _NL_CURRENT || !HAVE_STRFTIME
689 cpy (month_len
, f_month
);
692 goto underlying_strftime
;
699 if (! (modifier
== 'E'
700 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
)) != '\0'))
701 subfmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
704 goto underlying_strftime
;
706 subfmt
= "%a %b %e %H:%M:%S %Y";
713 size_t len
= my_strftime (NULL
, maxsize
- i
, subfmt
, tp
);
714 if (len
== 0 && *subfmt
)
716 add (len
, my_strftime (p
, maxsize
- i
, subfmt
, tp
));
719 while (old_start
< p
)
721 *old_start
= TOUPPER ((unsigned char) *old_start
);
727 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
730 /* The relevant information is available only via the
731 underlying strftime implementation, so use that. */
734 char ubuf
[1024]; /* enough for any single format in practice */
741 len
= strftime (ubuf
, sizeof ubuf
, ufmt
, tp
);
749 case 'C': /* POSIX.2 extension. */
754 #if HAVE_STRUCT_ERA_ENTRY
755 struct era_entry
*era
= _nl_get_era_entry (tp
);
758 size_t len
= strlen (era
->name_fmt
);
759 cpy (len
, era
->name_fmt
);
764 goto underlying_strftime
;
770 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
771 DO_NUMBER (1, year
/ 100 - (year
% 100 < 0));
778 if (! (modifier
== 'E'
779 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
)) != '\0'))
780 subfmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
784 goto underlying_strftime
;
789 case 'D': /* POSIX.2 extension. */
799 DO_NUMBER (2, tp
->tm_mday
);
801 case 'e': /* POSIX.2 extension. */
805 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
807 /* All numeric formats set DIGITS and NUMBER_VALUE and then
808 jump to one of these two labels. */
811 /* Force `_' flag unless overwritten by `0' flag. */
816 /* Format the number according to the MODIFIER flag. */
818 if (modifier
== 'O' && 0 <= number_value
)
821 /* Get the locale specific alternate representation of
822 the number NUMBER_VALUE. If none exist NULL is returned. */
823 const char *cp
= _nl_get_alt_digit (number_value
);
827 size_t digitlen
= strlen (cp
);
836 goto underlying_strftime
;
841 unsigned int u
= number_value
;
843 bufp
= buf
+ sizeof (buf
);
844 negative_number
= number_value
< 0;
850 *--bufp
= u
% 10 + '0';
851 while ((u
/= 10) != 0);
854 do_number_sign_and_padding
:
860 int padding
= digits
- (buf
+ sizeof (buf
) - bufp
);
864 while (0 < padding
--)
869 bufp
+= negative_number
;
870 while (0 < padding
--)
877 cpy (buf
+ sizeof (buf
) - bufp
, bufp
);
885 DO_NUMBER (2, tp
->tm_hour
);
891 DO_NUMBER (2, hour12
);
893 case 'k': /* GNU extension. */
897 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
899 case 'l': /* GNU extension. */
903 DO_NUMBER_SPACEPAD (2, hour12
);
909 DO_NUMBER (3, 1 + tp
->tm_yday
);
915 DO_NUMBER (2, tp
->tm_min
);
921 DO_NUMBER (2, tp
->tm_mon
+ 1);
923 case 'n': /* POSIX.2 extension. */
929 #if !defined _NL_CURRENT && HAVE_STRFTIME
940 #if defined _NL_CURRENT || !HAVE_STRFTIME
944 goto underlying_strftime
;
947 case 'R': /* GNU extension. */
951 case 'r': /* POSIX.2 extension. */
953 if (*(subfmt
= _NL_CURRENT (LC_TIME
, T_FMT_AMPM
)) == '\0')
955 subfmt
= "%I:%M:%S %p";
962 DO_NUMBER (2, tp
->tm_sec
);
964 case 's': /* GNU extension. */
972 /* Generate string value for T using time_t arithmetic;
973 this works even if sizeof (long) < sizeof (time_t). */
975 bufp
= buf
+ sizeof (buf
);
976 negative_number
= t
< 0;
987 /* Adjust if division truncates to minus infinity. */
988 if (0 < -1 % 10 && d
< 0)
1000 goto do_number_sign_and_padding
;
1004 if (modifier
== 'O')
1007 if (! (modifier
== 'E'
1008 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
)) != '\0'))
1009 subfmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
1013 goto underlying_strftime
;
1018 case 'T': /* POSIX.2 extension. */
1019 subfmt
= "%H:%M:%S";
1022 case 't': /* POSIX.2 extension. */
1026 case 'u': /* POSIX.2 extension. */
1027 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
1030 if (modifier
== 'E')
1033 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
1036 case 'g': /* GNU extension. */
1037 case 'G': /* GNU extension. */
1038 if (modifier
== 'E')
1041 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
1042 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
1046 /* This ISO week belongs to the previous year. */
1048 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
)),
1053 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
1057 /* This ISO week belongs to the next year. */
1066 DO_NUMBER (2, (year
% 100 + 100) % 100);
1069 DO_NUMBER (1, year
);
1072 DO_NUMBER (2, days
/ 7 + 1);
1077 if (modifier
== 'E')
1080 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
1083 if (modifier
== 'E')
1086 DO_NUMBER (1, tp
->tm_wday
);
1089 if (modifier
== 'E')
1091 #if HAVE_STRUCT_ERA_ENTRY
1092 struct era_entry
*era
= _nl_get_era_entry (tp
);
1095 subfmt
= strchr (era
->name_fmt
, '\0') + 1;
1100 goto underlying_strftime
;
1104 if (modifier
== 'O')
1107 DO_NUMBER (1, tp
->tm_year
+ TM_YEAR_BASE
);
1110 if (modifier
== 'E')
1112 #if HAVE_STRUCT_ERA_ENTRY
1113 struct era_entry
*era
= _nl_get_era_entry (tp
);
1116 int delta
= tp
->tm_year
- era
->start_date
[0];
1117 DO_NUMBER (1, (era
->offset
1118 + (era
->direction
== '-' ? -delta
: delta
)));
1122 goto underlying_strftime
;
1126 DO_NUMBER (2, (tp
->tm_year
% 100 + 100) % 100);
1134 cpy (zonelen
, zone
);
1137 case 'z': /* GNU extension. */
1138 if (tp
->tm_isdst
< 0)
1144 diff
= tp
->tm_gmtoff
;
1153 if (lt
== (time_t) -1)
1155 /* mktime returns -1 for errors, but -1 is also a
1156 valid time_t value. Check whether an error really
1159 localtime_r (<
, &tm
);
1161 if ((ltm
.tm_sec
^ tm
.tm_sec
)
1162 | (ltm
.tm_min
^ tm
.tm_min
)
1163 | (ltm
.tm_hour
^ tm
.tm_hour
)
1164 | (ltm
.tm_mday
^ tm
.tm_mday
)
1165 | (ltm
.tm_mon
^ tm
.tm_mon
)
1166 | (ltm
.tm_year
^ tm
.tm_year
))
1170 if (! gmtime_r (<
, >m
))
1173 diff
= tm_diff (<m
, >m
);
1185 DO_NUMBER (4, (diff
/ 60) * 100 + diff
% 60);
1188 case '\0': /* GNU extension: % at end of format. */
1192 /* Unknown format; output the format, including the '%',
1193 since this is most likely the right thing to do if a
1194 multibyte string has been misparsed. */
1198 for (flen
= 1; f
[1 - flen
] != '%'; flen
++)
1200 cpy (flen
, &f
[1 - flen
]);