1 /* Copyright (C) 1991-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
9 This file 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
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 # define FPRINTFTIME 0
22 # define USE_C_LOCALE 0
26 # define USE_IN_EXTENDED_LOCALE_MODEL 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_TM_GMTOFF 1
29 # define HAVE_STRUCT_TM_TM_ZONE 1
30 # define HAVE_TZNAME 1
31 # include "../locale/localeinfo.h"
33 # include <libc-config.h>
35 # include "fprintftime.h"
37 # include "strftime.h"
39 # include "time-internal.h"
42 /* Whether to require GNU behavior for AM and PM indicators, even on
43 other platforms. This matters only in non-C locales.
44 The default is to require it; you can override this via
45 AC_DEFINE([REQUIRE_GNUISH_STRFTIME_AM_PM], 1) and if you do that
46 you may be able to omit Gnulib's localename module and its dependencies. */
47 #ifndef REQUIRE_GNUISH_STRFTIME_AM_PM
48 # define REQUIRE_GNUISH_STRFTIME_AM_PM true
51 # undef REQUIRE_GNUISH_STRFTIME_AM_PM
52 # define REQUIRE_GNUISH_STRFTIME_AM_PM false
63 #if HAVE_TZNAME && !HAVE_DECL_TZNAME
64 extern char *tzname
[];
67 /* Do multibyte processing if multibyte encodings are supported, unless
68 multibyte sequences are safe in formats. Multibyte sequences are
69 safe if they cannot contain byte sequences that look like format
70 conversion specifications. The multibyte encodings used by the
71 C library on the various platforms (UTF-8, GB2312, GBK, CP936,
72 GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
73 SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
74 cannot occur in a multibyte character except in the first byte.
76 The DEC-HANYU encoding used on OSF/1 is not safe for formats, but
77 this encoding has never been seen in real-life use, so we ignore
79 #if !(defined __osf__ && 0)
80 # define MULTIBYTE_IS_FORMAT_SAFE 1
82 #define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
86 static const mbstate_t mbstate_zero
;
90 #include <stdckdint.h>
95 #if USE_C_LOCALE && HAVE_STRFTIME_L
99 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
101 # include "localename.h"
104 #include "attribute.h"
105 #include <intprops.h>
109 # define CHAR_T wchar_t
110 # define UCHAR_T unsigned int
111 # define L_(Str) L##Str
112 # define NLW(Sym) _NL_W##Sym
114 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
115 # define STRLEN(s) __wcslen (s)
119 # define UCHAR_T unsigned char
121 # define NLW(Sym) Sym
122 # define ABALTMON_1 _NL_ABALTMON_1
124 # define MEMCPY(d, s, n) memcpy (d, s, n)
125 # define STRLEN(s) strlen (s)
129 /* Shift A right by B bits portably, by dividing A by 2**B and
130 truncating towards minus infinity. A and B should be free of side
131 effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
132 INT_BITS is the number of useful bits in an int. GNU code can
133 assume that INT_BITS is at least 32.
135 ISO C99 says that A >> B is implementation-defined if A < 0. Some
136 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
137 right in the usual way when A < 0, so SHR falls back on division if
138 ordinary A >> B doesn't seem to be the usual signed shift. */
142 : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
144 #define TM_YEAR_BASE 1900
147 /* Nonzero if YEAR is a leap year (every 4 years,
148 except every 100th isn't, and every 400th is). */
149 # define __isleap(year) \
150 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
155 # define mktime_z(tz, tm) mktime (tm)
156 # define tzname __tzname
157 # define tzset __tzset
159 # define time_t __time64_t
160 # define __gmtime_r(t, tp) __gmtime64_r (t, tp)
161 # define mktime(tp) __mktime64 (tp)
165 # define STREAM_OR_CHAR_T FILE
166 # define STRFTIME_ARG(x) /* empty */
168 # define STREAM_OR_CHAR_T CHAR_T
169 # define STRFTIME_ARG(x) x,
173 # define memset_byte(P, Len, Byte) \
174 do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
175 # define memset_space(P, Len) memset_byte (P, Len, ' ')
176 # define memset_zero(P, Len) memset_byte (P, Len, '0')
177 #elif defined COMPILE_WIDE
178 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
179 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
181 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
182 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
186 # define advance(P, N)
188 # define advance(P, N) ((P) += (N))
191 #define add(n, f) width_add (width, n, f)
192 #define width_add(width, n, f) \
196 size_t _w = pad == L_('-') || width < 0 ? 0 : width; \
197 size_t _incr = _n < _w ? _w : _n; \
198 if (_incr >= maxsize - i) \
207 size_t _delta = _w - _n; \
208 if (pad == L_('0') || pad == L_('+')) \
209 memset_zero (p, _delta); \
211 memset_space (p, _delta); \
219 #define add1(c) width_add1 (width, c)
221 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
223 # define width_add1(width, c) width_add (width, 1, *p = c)
226 #define cpy(n, s) width_cpy (width, n, s)
228 # define width_cpy(width, n, s) \
229 width_add (width, n, \
233 fwrite_lowcase (p, (s), _n); \
234 else if (to_uppcase) \
235 fwrite_uppcase (p, (s), _n); \
238 /* Ignore the value of fwrite. The caller can determine whether \
239 an error occurred by inspecting ferror (P). All known fwrite \
240 implementations set the stream's error indicator when they \
241 fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do \
242 not require this. */ \
243 fwrite (s, _n, 1, p); \
249 # define width_cpy(width, n, s) \
250 width_add (width, n, \
252 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
253 else if (to_uppcase) \
254 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
256 MEMCPY ((void *) p, (void const *) (s), _n))
260 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
261 # undef __mbsrtowcs_l
262 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
267 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
268 /* We use this code also for the extended locale handling where the
269 function gets as an additional argument the locale which has to be
270 used. To access the values we have to redefine the _NL_CURRENT
272 # define strftime __strftime_l
273 # define wcsftime __wcsftime_l
275 # define _NL_CURRENT(category, item) \
276 (current->values[_NL_ITEM_INDEX (item)].string)
277 # define LOCALE_PARAM , locale_t loc
278 # define LOCALE_ARG , loc
279 # define HELPER_LOCALE_ARG , current
281 # define LOCALE_PARAM
284 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
286 # define HELPER_LOCALE_ARG
291 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
292 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
293 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
295 # define TOUPPER(Ch, L) towupper (Ch)
296 # define TOLOWER(Ch, L) towlower (Ch)
299 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
300 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
301 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
304 # define TOUPPER(Ch, L) c_toupper (Ch)
305 # define TOLOWER(Ch, L) c_tolower (Ch)
307 # define TOUPPER(Ch, L) toupper (Ch)
308 # define TOLOWER(Ch, L) tolower (Ch)
312 /* We don't use 'isdigit' here since the locale dependent
313 interpretation is not what we want here. We only need to accept
314 the arabic digits in the ASCII range. One day there is perhaps a
315 more reliable way to accept other sets of digits. */
316 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
318 /* Avoid false GCC warning "'memset' specified size 18446744073709551615 exceeds
319 maximum object size 9223372036854775807", caused by insufficient data flow
320 analysis and value propagation of the 'width_add' expansion when GCC is not
321 optimizing. Cf. <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443>. */
322 #if __GNUC__ >= 7 && !__OPTIMIZE__
323 # pragma GCC diagnostic ignored "-Wstringop-overflow"
328 fwrite_lowcase (FILE *fp
, const CHAR_T
*src
, size_t len
)
332 fputc (TOLOWER ((UCHAR_T
) *src
, loc
), fp
);
338 fwrite_uppcase (FILE *fp
, const CHAR_T
*src
, size_t len
)
342 fputc (TOUPPER ((UCHAR_T
) *src
, loc
), fp
);
347 static CHAR_T
*memcpy_lowcase (CHAR_T
*dest
, const CHAR_T
*src
,
348 size_t len LOCALE_PARAM
);
351 memcpy_lowcase (CHAR_T
*dest
, const CHAR_T
*src
, size_t len LOCALE_PARAM
)
354 dest
[len
] = TOLOWER ((UCHAR_T
) src
[len
], loc
);
358 static CHAR_T
*memcpy_uppcase (CHAR_T
*dest
, const CHAR_T
*src
,
359 size_t len LOCALE_PARAM
);
362 memcpy_uppcase (CHAR_T
*dest
, const CHAR_T
*src
, size_t len LOCALE_PARAM
)
365 dest
[len
] = TOUPPER ((UCHAR_T
) src
[len
], loc
);
371 #if USE_C_LOCALE && HAVE_STRFTIME_L
373 /* Cache for the C locale object.
374 Marked volatile so that different threads see the same value
376 static volatile locale_t c_locale_cache
;
378 /* Return the C locale object, or (locale_t) 0 with errno set
379 if it cannot be created. */
384 c_locale_cache
= newlocale (LC_ALL_MASK
, "C", (locale_t
) 0);
385 return c_locale_cache
;
391 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
393 /* Return true if an AM/PM indicator should be removed. */
395 should_remove_ampm (void)
397 /* According to glibc's 'am_pm' attribute in the locale database, an AM/PM
398 indicator should be absent in the locales for the following languages:
399 ab an ast az be ber bg br bs ce cs csb cv da de dsb eo et eu fa fi fo fr
400 fur fy ga gl gv hr hsb ht hu hy it ka kk kl ku kv kw ky lb lg li lij ln
401 lt lv mg mhr mi mk mn ms mt nb nds nhn nl nn nr nso oc os pap pl pt ro
402 ru rw sah sc se sgs sk sl sm sr ss st su sv szl tg tk tn ts tt ug uk unm
403 uz ve wae wo xh zu */
404 const char *loc
= gl_locale_name_unsafe (LC_TIME
, "LC_TIME");
405 bool remove_ampm
= false;
411 case 'b': case 'n': case 'z':
412 if (loc
[2] == '\0' || loc
[2] == '_')
416 if (loc
[2] == 't' && (loc
[3] == '\0' || loc
[3] == '_'))
427 if (loc
[2] == '\0' || loc
[2] == '_'
428 || (loc
[2] == 'r' && (loc
[3] == '\0' || loc
[3] == '_')))
431 case 'g': case 'r': case 's':
432 if (loc
[2] == '\0' || loc
[2] == '_')
443 if (loc
[2] == '\0' || loc
[2] == '_')
447 if (loc
[2] == '\0' || loc
[2] == '_'
448 || (loc
[2] == 'b' && (loc
[3] == '\0' || loc
[3] == '_')))
459 if (loc
[2] == '\0' || loc
[2] == '_')
463 if (loc
[2] == 'b' && (loc
[3] == '\0' || loc
[3] == '_'))
473 case 'o': case 't': case 'u':
474 if (loc
[2] == '\0' || loc
[2] == '_')
484 case 'a': case 'i': case 'o': case 'r': case 'y':
485 if (loc
[2] == '\0' || loc
[2] == '_')
489 if (loc
[2] == 'r' && (loc
[3] == '\0' || loc
[3] == '_'))
499 case 'a': case 'l': case 'v':
500 if (loc
[2] == '\0' || loc
[2] == '_')
510 case 'r': case 't': case 'u': case 'y':
511 if (loc
[2] == '\0' || loc
[2] == '_')
515 if (loc
[2] == 'b' && (loc
[3] == '\0' || loc
[3] == '_'))
526 if (loc
[2] == '\0' || loc
[2] == '_')
536 case 'a': case 'k': case 'l': case 'u': case 'v': case 'w': case 'y':
537 if (loc
[2] == '\0' || loc
[2] == '_')
547 case 'b': case 'g': case 'n': case 't': case 'v':
548 if (loc
[2] == '\0' || loc
[2] == '_')
552 if (loc
[2] == 'j' && (loc
[3] == '\0' || loc
[3] == '_'))
562 case 'g': case 'i': case 'k': case 'n': case 's': case 't':
563 if (loc
[2] == '\0' || loc
[2] == '_')
567 if (loc
[2] == 'r' && (loc
[3] == '\0' || loc
[3] == '_'))
577 case 'b': case 'l': case 'n': case 'r':
578 if (loc
[2] == '\0' || loc
[2] == '_')
582 if (loc
[2] == 's' && (loc
[3] == '\0' || loc
[3] == '_'))
586 if (loc
[2] == 'n' && (loc
[3] == '\0' || loc
[3] == '_'))
590 if (loc
[2] == 'o' && (loc
[3] == '\0' || loc
[3] == '_'))
601 if (loc
[2] == '\0' || loc
[2] == '_')
612 if (loc
[2] == '\0' || loc
[2] == '_')
616 if (loc
[2] == 'p' && (loc
[3] == '\0' || loc
[3] == '_'))
626 case 'o': case 'u': case 'w':
627 if (loc
[2] == '\0' || loc
[2] == '_')
637 case 'c': case 'e': case 'k': case 'l': case 'm': case 'r': case 's':
638 case 't': case 'u': case 'v':
639 if (loc
[2] == '\0' || loc
[2] == '_')
643 if (loc
[2] == 'h' && (loc
[3] == '\0' || loc
[3] == '_'))
647 if (loc
[2] == 's' && (loc
[3] == '\0' || loc
[3] == '_'))
651 if (loc
[2] == 'l' && (loc
[3] == '\0' || loc
[3] == '_'))
661 case 'g': case 'k': case 'n': case 's': case 't':
662 if (loc
[2] == '\0' || loc
[2] == '_')
672 case 'g': case 'k': case 'z':
673 if (loc
[2] == '\0' || loc
[2] == '_')
677 if (loc
[2] == 'm'&& (loc
[3] == '\0' || loc
[3] == '_'))
688 if (loc
[2] == '\0' || loc
[2] == '_')
699 if (loc
[2] == 'e' && (loc
[3] == '\0' || loc
[3] == '_'))
703 if (loc
[2] == '\0' || loc
[2] == '_')
714 if (loc
[2] == '\0' || loc
[2] == '_')
725 if (loc
[2] == '\0' || loc
[2] == '_')
742 /* Yield the difference between *A and *B,
743 measured in seconds, ignoring leap seconds. */
744 # define tm_diff ftime_tm_diff
745 static int tm_diff (const struct tm
*, const struct tm
*);
747 tm_diff (const struct tm
*a
, const struct tm
*b
)
749 /* Compute intervening leap days correctly even if year is negative.
750 Take care to avoid int overflow in leap day calculations,
751 but it's OK to assume that A and B are close to each other. */
752 int a4
= SHR (a
->tm_year
, 2) + SHR (TM_YEAR_BASE
, 2) - ! (a
->tm_year
& 3);
753 int b4
= SHR (b
->tm_year
, 2) + SHR (TM_YEAR_BASE
, 2) - ! (b
->tm_year
& 3);
754 int a100
= (a4
+ (a4
< 0)) / 25 - (a4
< 0);
755 int b100
= (b4
+ (b4
< 0)) / 25 - (b4
< 0);
756 int a400
= SHR (a100
, 2);
757 int b400
= SHR (b100
, 2);
758 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
759 int years
= a
->tm_year
- b
->tm_year
;
760 int days
= (365 * years
+ intervening_leap_days
761 + (a
->tm_yday
- b
->tm_yday
));
762 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
763 + (a
->tm_min
- b
->tm_min
))
764 + (a
->tm_sec
- b
->tm_sec
));
766 #endif /* ! HAVE_TM_GMTOFF */
770 /* The number of days from the first day of the first ISO week of this
771 year to the year day YDAY with week day WDAY. ISO weeks start on
772 Monday; the first ISO week has the year's first Thursday. YDAY may
773 be as small as YDAY_MINIMUM. */
774 #define ISO_WEEK_START_WDAY 1 /* Monday */
775 #define ISO_WEEK1_WDAY 4 /* Thursday */
776 #define YDAY_MINIMUM (-366)
777 static int iso_week_days (int, int);
779 iso_week_days (int yday
, int wday
)
781 /* Add enough to the first operand of % to make it nonnegative. */
782 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
784 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
785 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
789 #if !defined _NL_CURRENT && (USE_C_LOCALE && !HAVE_STRFTIME_L)
790 static CHAR_T
const c_weekday_names
[][sizeof "Wednesday"] =
792 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
793 L_("Thursday"), L_("Friday"), L_("Saturday")
795 static CHAR_T
const c_month_names
[][sizeof "September"] =
797 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
798 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
799 L_("November"), L_("December")
804 /* When compiling this file, GNU applications can #define my_strftime
805 to a symbol (typically nstrftime) to get an extended strftime with
806 extra arguments TZ and NS. */
809 # define extra_args , tz, ns
810 # define extra_args_spec , timezone_t tz, int ns
812 # if defined COMPILE_WIDE
813 # define my_strftime wcsftime
814 # define nl_get_alt_digit _nl_get_walt_digit
816 # define my_strftime strftime
817 # define nl_get_alt_digit _nl_get_alt_digit
820 # define extra_args_spec
821 /* We don't have this information in general. */
826 static size_t __strftime_internal (STREAM_OR_CHAR_T
*, STRFTIME_ARG (size_t)
827 const CHAR_T
*, const struct tm
*,
828 bool, int, int, bool *
829 extra_args_spec LOCALE_PARAM
);
831 /* Write information from TP into S according to the format
832 string FORMAT, writing no more that MAXSIZE characters
833 (including the terminating '\0') and returning number of
834 characters written. If S is NULL, nothing will be written
835 anywhere, so to determine how many characters would be
836 written, use NULL for S and (size_t) -1 for MAXSIZE. */
838 my_strftime (STREAM_OR_CHAR_T
*s
, STRFTIME_ARG (size_t maxsize
)
839 const CHAR_T
*format
,
840 const struct tm
*tp extra_args_spec LOCALE_PARAM
)
842 bool tzset_called
= false;
843 return __strftime_internal (s
, STRFTIME_ARG (maxsize
) format
, tp
, false,
844 0, -1, &tzset_called extra_args LOCALE_ARG
);
846 libc_hidden_def (my_strftime
)
848 /* Just like my_strftime, above, but with more parameters.
849 UPCASE indicates that the result should be converted to upper case.
850 YR_SPEC and WIDTH specify the padding and width for the year.
851 *TZSET_CALLED indicates whether tzset has been called here. */
853 __strftime_internal (STREAM_OR_CHAR_T
*s
, STRFTIME_ARG (size_t maxsize
)
854 const CHAR_T
*format
,
855 const struct tm
*tp
, bool upcase
,
856 int yr_spec
, int width
, bool *tzset_called
857 extra_args_spec LOCALE_PARAM
)
859 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
860 struct __locale_data
*const current
= loc
->__locales
[LC_TIME
];
863 size_t maxsize
= (size_t) -1;
866 int saved_errno
= errno
;
867 int hour12
= tp
->tm_hour
;
869 /* We cannot make the following values variables since we must delay
870 the evaluation of these values until really needed since some
871 expressions might not be valid in every situation. The 'struct tm'
872 might be generated by a strptime() call that initialized
873 only a few elements. Dereference the pointers only if the format
874 requires this. Then it is ok to fail if the pointers are invalid. */
876 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
877 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
879 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
880 ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
882 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
883 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
885 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
886 ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
887 # define a_altmonth \
888 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
889 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
890 # define f_altmonth \
891 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
892 ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
894 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
895 ? NLW(PM_STR) : NLW(AM_STR)))
897 # define aw_len STRLEN (a_wkday)
898 # define am_len STRLEN (a_month)
899 # define aam_len STRLEN (a_altmonth)
900 # define ap_len STRLEN (ampm)
901 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
902 /* The English abbreviated weekday names are just the first 3 characters of the
903 English full weekday names. */
905 (tp->tm_wday < 0 || tp->tm_wday > 6 ? L_("?") : c_weekday_names[tp->tm_wday])
908 (tp->tm_wday < 0 || tp->tm_wday > 6 ? L_("?") : c_weekday_names[tp->tm_wday])
909 /* The English abbreviated month names are just the first 3 characters of the
910 English full month names. */
912 (tp->tm_mon < 0 || tp->tm_mon > 11 ? L_("?") : c_month_names[tp->tm_mon])
915 (tp->tm_mon < 0 || tp->tm_mon > 11 ? L_("?") : c_month_names[tp->tm_mon])
916 /* The English AM/PM strings happen to have the same length, namely 2. */
917 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
921 char **tzname_vec
= tzname
;
925 STREAM_OR_CHAR_T
*p
= s
;
927 #if DO_MULTIBYTE && !defined COMPILE_WIDE
928 const char *format_end
= NULL
;
932 #if HAVE_STRUCT_TM_TM_ZONE
933 /* The POSIX test suite assumes that setting
934 the environment variable TZ to a new value before calling strftime()
935 will influence the result (the %Z format) even if the information in
936 TP is computed with a totally different time zone.
937 This is bogus: though POSIX allows bad behavior like this,
938 POSIX does not require it. Do the right thing instead. */
939 zone
= (const char *) tp
->tm_zone
;
944 if (! (zone
&& *zone
))
949 # if !HAVE_STRUCT_TM_TM_ZONE
950 /* Infer the zone name from *TZ instead of from TZNAME. */
951 tzname_vec
= tz
->tzname_copy
;
954 /* The tzset() call might have changed the value. */
955 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
957 /* POSIX.1 requires that local time zone information be used as
958 though strftime called tzset. */
963 *tzset_called
= true;
966 zone
= tzname_vec
[tp
->tm_isdst
!= 0];
978 for (f
= format
; *f
!= '\0'; width
= -1, f
++)
980 int pad
= 0; /* Padding for number ('_', '-', '+', '0', or 0). */
981 int modifier
; /* Field modifier ('E', 'O', or 0). */
982 int digits
= 0; /* Max digits for numeric format. */
983 int number_value
; /* Numeric value to be printed. */
984 unsigned int u_number_value
; /* (unsigned int) number_value. */
985 bool negative_number
; /* The number is negative. */
986 bool always_output_a_sign
; /* +/- should always be output. */
987 int tz_colon_mask
; /* Bitmask of where ':' should appear. */
988 const CHAR_T
*subfmt
;
991 + 2 /* for the two colons in a %::z or %:::z time zone */
992 + (sizeof (int) < sizeof (time_t)
993 ? INT_STRLEN_BOUND (time_t)
994 : INT_STRLEN_BOUND (int))];
995 bool to_lowcase
= false;
996 bool to_uppcase
= upcase
;
998 bool change_case
= false;
1002 #if DO_MULTIBYTE && !defined COMPILE_WIDE
1008 case L_('\b'): case L_('\t'): case L_('\n'):
1009 case L_('\v'): case L_('\f'): case L_('\r'):
1010 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
1011 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
1012 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
1013 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
1014 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
1015 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
1016 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
1017 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
1018 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
1019 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
1020 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
1021 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
1022 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
1023 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
1024 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
1025 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
1026 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
1027 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
1029 /* The C Standard requires these 98 characters (plus '%') to
1030 be in the basic execution character set. None of these
1031 characters can start a multibyte sequence, so they need
1032 not be analyzed further. */
1037 /* Copy this multibyte sequence until we reach its end, find
1038 an error, or come back to the initial shift state. */
1040 mbstate_t mbstate
= mbstate_zero
;
1045 format_end
= f
+ strlen (f
) + 1;
1046 fsize
= format_end
- f
;
1050 size_t bytes
= mbrlen (f
+ len
, fsize
- len
, &mbstate
);
1055 if (bytes
== (size_t) -2)
1057 len
+= strlen (f
+ len
);
1061 if (bytes
== (size_t) -1)
1069 while (! mbsinit (&mbstate
));
1077 #else /* ! DO_MULTIBYTE */
1079 /* Either multibyte encodings are not supported, they are
1080 safe for formats, so any non-'%' byte can be copied through,
1081 or this is the wide character version. */
1088 #endif /* ! DO_MULTIBYTE */
1090 char const *percent
= f
;
1092 /* Check for flags that can modify a format. */
1097 /* This influences the number formats. */
1105 /* This changes textual output. */
1124 if (ckd_mul (&width
, width
, 10)
1125 || ckd_add (&width
, width
, *f
- L_('0')))
1129 while (ISDIGIT (*f
));
1132 /* Check for modifiers. */
1145 /* Now do the specified format. */
1147 switch (format_char
)
1149 #define DO_NUMBER(d, v) \
1157 #define DO_SIGNED_NUMBER(d, negative, v) \
1158 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
1159 #define DO_YEARISH(d, negative, v) \
1160 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
1161 #define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
1165 negative_number = negative; \
1166 u_number_value = v; \
1171 /* The mask is not what you might think.
1172 When the ordinal i'th bit is set, insert a colon
1173 before the i'th digit of the time zone representation. */
1174 #define DO_TZ_OFFSET(d, mask, v) \
1178 tz_colon_mask = mask; \
1179 u_number_value = v; \
1180 goto do_tz_offset; \
1183 #define DO_NUMBER_SPACEPAD(d, v) \
1188 goto do_number_spacepad; \
1193 if (f
- 1 != percent
)
1206 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1207 cpy (aw_len
, a_wkday
);
1210 goto underlying_strftime
;
1221 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1222 cpy (STRLEN (f_wkday
), f_wkday
);
1225 goto underlying_strftime
;
1235 if (modifier
== L_('E'))
1238 if (modifier
== L_('O'))
1239 cpy (aam_len
, a_altmonth
);
1241 cpy (am_len
, a_month
);
1243 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1244 cpy (am_len
, a_month
);
1247 goto underlying_strftime
;
1251 if (modifier
== L_('E'))
1259 if (modifier
== L_('O'))
1260 cpy (STRLEN (f_altmonth
), f_altmonth
);
1262 cpy (STRLEN (f_month
), f_month
);
1264 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1265 cpy (STRLEN (f_month
), f_month
);
1268 goto underlying_strftime
;
1272 if (modifier
== L_('O'))
1275 if (! (modifier
== L_('E')
1277 (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
1280 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_T_FMT
));
1281 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1282 subfmt
= L_("%a %b %e %H:%M:%S %Y");
1284 goto underlying_strftime
;
1291 size_t len
= __strftime_internal (NULL
, STRFTIME_ARG ((size_t) -1)
1292 subfmt
, tp
, to_uppcase
,
1293 pad
, subwidth
, tzset_called
1294 extra_args LOCALE_ARG
);
1295 add (len
, __strftime_internal (p
,
1296 STRFTIME_ARG (maxsize
- i
)
1297 subfmt
, tp
, to_uppcase
,
1298 pad
, subwidth
, tzset_called
1299 extra_args LOCALE_ARG
));
1303 #if !((defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY) || (USE_C_LOCALE && !HAVE_STRFTIME_L))
1304 underlying_strftime
:
1306 /* The relevant information is available only via the
1307 underlying strftime implementation, so use that. */
1310 char ubuf
[1024]; /* enough for any single format in practice */
1312 /* Make sure we're calling the actual underlying strftime.
1313 In some cases, config.h contains something like
1314 "#define strftime rpl_strftime". */
1317 size_t strftime (char *, size_t, const char *, struct tm
const *);
1320 /* The space helps distinguish strftime failure from empty
1329 # if USE_C_LOCALE /* implies HAVE_STRFTIME_L */
1330 locale_t locale
= c_locale ();
1332 return 0; /* errno is set here */
1333 len
= strftime_l (ubuf
, sizeof ubuf
, ufmt
, tp
, locale
);
1335 len
= strftime (ubuf
, sizeof ubuf
, ufmt
, tp
);
1339 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) || defined __NetBSD__ || defined __sun /* glibc < 2.31, NetBSD, Solaris */
1340 if (format_char
== L_('c'))
1342 /* The output of the strftime %c directive consists of the
1343 date, the time, and the time zone. But the time zone is
1344 wrong, since neither TZ nor ZONE was passed as argument.
1345 Therefore, remove the the last space-delimited word.
1346 In order not to accidentally remove a date or a year
1347 (that contains no letter) or an AM/PM indicator (that has
1348 length 2), remove that last word only if it contains a
1349 letter and has length >= 3. */
1351 for (space
= ubuf
+ len
- 1; *space
!= ' '; space
--)
1355 /* Found a space. */
1356 if (strlen (space
+ 1) >= 3)
1358 /* The last word has length >= 3. */
1359 bool found_letter
= false;
1361 for (p
= space
+ 1; *p
!= '\0'; p
++)
1362 if ((*p
>= 'A' && *p
<= 'Z')
1363 || (*p
>= 'a' && *p
<= 'z'))
1365 found_letter
= true;
1370 /* The last word contains a letter. */
1377 # if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
1378 /* The output of the strftime %p and %r directives contains
1379 an AM/PM indicator even for locales where it is not
1380 suitable, such as French. Remove this indicator. */
1381 else if (format_char
== L_('p'))
1383 bool found_ampm
= (len
> 1);
1384 if (found_ampm
&& should_remove_ampm ())
1390 else if (format_char
== L_('r'))
1392 char last_char
= ubuf
[len
- 1];
1393 bool found_ampm
= !(last_char
>= '0' && last_char
<= '9');
1394 if (found_ampm
&& should_remove_ampm ())
1397 for (space
= ubuf
+ len
- 1; *space
!= ' '; space
--)
1408 cpy (len
- 1, ubuf
+ 1);
1415 if (modifier
== L_('E'))
1417 #if HAVE_STRUCT_ERA_ENTRY
1418 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1421 # ifdef COMPILE_WIDE
1422 size_t len
= __wcslen (era
->era_wname
);
1423 cpy (len
, era
->era_wname
);
1425 size_t len
= strlen (era
->era_name
);
1426 cpy (len
, era
->era_name
);
1430 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1432 goto underlying_strftime
;
1437 bool negative_year
= tp
->tm_year
< - TM_YEAR_BASE
;
1438 bool zero_thru_1899
= !negative_year
& (tp
->tm_year
< 0);
1439 int century
= ((tp
->tm_year
- 99 * zero_thru_1899
) / 100
1440 + TM_YEAR_BASE
/ 100);
1441 DO_YEARISH (2, negative_year
, century
);
1445 if (modifier
== L_('O'))
1448 if (! (modifier
== L_('E')
1450 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_D_FMT
)))
1452 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_FMT
));
1454 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1455 subfmt
= L_("%m/%d/%y");
1458 goto underlying_strftime
;
1463 subfmt
= L_("%m/%d/%y");
1467 if (modifier
== L_('E'))
1470 DO_NUMBER (2, tp
->tm_mday
);
1473 if (modifier
== L_('E'))
1476 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
1478 /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
1479 and then jump to one of these labels. */
1482 always_output_a_sign
= true;
1483 goto do_number_body
;
1488 always_output_a_sign
1490 && ((digits
== 2 ? 99 : 9999) < u_number_value
1491 || digits
< width
));
1492 goto do_maybe_signed_number
;
1499 /* Format NUMBER_VALUE according to the MODIFIER flag. */
1500 negative_number
= number_value
< 0;
1501 u_number_value
= number_value
;
1504 always_output_a_sign
= false;
1506 do_maybe_signed_number
:
1510 /* Format U_NUMBER_VALUE according to the MODIFIER flag.
1511 NEGATIVE_NUMBER is nonzero if the original number was
1512 negative; in this case it was converted directly to
1513 unsigned int (i.e., modulo (UINT_MAX + 1)) without
1515 if (modifier
== L_('O') && !negative_number
)
1518 /* Get the locale specific alternate representation of
1519 the number. If none exist NULL is returned. */
1520 const CHAR_T
*cp
= nl_get_alt_digit (u_number_value
1525 size_t digitlen
= STRLEN (cp
);
1532 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1534 goto underlying_strftime
;
1538 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1540 if (negative_number
)
1541 u_number_value
= - u_number_value
;
1545 if (tz_colon_mask
& 1)
1547 tz_colon_mask
>>= 1;
1548 *--bufp
= u_number_value
% 10 + L_('0');
1549 u_number_value
/= 10;
1551 while (u_number_value
!= 0 || tz_colon_mask
!= 0);
1553 do_number_sign_and_padding
:
1560 CHAR_T sign_char
= (negative_number
? L_('-')
1561 : always_output_a_sign
? L_('+')
1563 int numlen
= buf
+ sizeof buf
/ sizeof buf
[0] - bufp
;
1564 int shortage
= width
- !!sign_char
- numlen
;
1565 int padding
= pad
== L_('-') || shortage
<= 0 ? 0 : shortage
;
1572 memset_space (p
, padding
);
1576 width_add1 (0, sign_char
);
1587 if (pad
== 0 && width
< 0)
1594 subwidth
= width
- 6;
1598 subfmt
= L_("%Y-%m-%d");
1599 goto subformat_width
;
1602 if (modifier
== L_('E'))
1605 DO_NUMBER (2, tp
->tm_hour
);
1608 if (modifier
== L_('E'))
1611 DO_NUMBER (2, hour12
);
1613 case L_('k'): /* GNU extension. */
1614 if (modifier
== L_('E'))
1617 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
1619 case L_('l'): /* GNU extension. */
1620 if (modifier
== L_('E'))
1623 DO_NUMBER_SPACEPAD (2, hour12
);
1626 if (modifier
== L_('E'))
1629 DO_SIGNED_NUMBER (3, tp
->tm_yday
< -1, tp
->tm_yday
+ 1U);
1632 if (modifier
== L_('E'))
1635 DO_NUMBER (2, tp
->tm_min
);
1638 if (modifier
== L_('E'))
1641 DO_SIGNED_NUMBER (2, tp
->tm_mon
< -1, tp
->tm_mon
+ 1U);
1644 case L_('N'): /* GNU extension. */
1645 if (modifier
== L_('E'))
1648 int n
= ns
, ns_digits
= 9;
1651 int ndigs
= ns_digits
;
1652 while (width
< ndigs
|| (1 < ndigs
&& n
% 10 == 0))
1654 for (int j
= ndigs
; 0 < j
; j
--)
1655 buf
[j
- 1] = n
% 10 + L_('0'), n
/= 10;
1658 width_cpy (0, ndigs
, buf
);
1659 width_add (width
- ndigs
, 0, (void) 0);
1671 format_char
= L_('p');
1680 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1684 goto underlying_strftime
;
1687 case L_('q'): /* GNU extension. */
1688 DO_SIGNED_NUMBER (1, false, ((tp
->tm_mon
* 11) >> 5) + 1);
1691 subfmt
= L_("%H:%M");
1696 if (*(subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
1699 subfmt
= L_("%I:%M:%S %p");
1701 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1702 subfmt
= L_("%I:%M:%S %p");
1704 #elif (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__
1705 /* macOS, FreeBSD strftime() may produce empty output for "%r". */
1706 subfmt
= L_("%I:%M:%S %p");
1709 goto underlying_strftime
;
1713 if (modifier
== L_('E'))
1716 DO_NUMBER (2, tp
->tm_sec
);
1718 case L_('s'): /* GNU extension. */
1725 t
= mktime_z (tz
, <m
);
1726 if (ltm
.tm_yday
< 0)
1732 /* Generate string value for T using time_t arithmetic;
1733 this works even if sizeof (long) < sizeof (time_t). */
1735 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1736 negative_number
= t
< 0;
1742 *--bufp
= (negative_number
? -d
: d
) + L_('0');
1747 always_output_a_sign
= false;
1748 goto do_number_sign_and_padding
;
1752 if (modifier
== L_('O'))
1755 if (! (modifier
== L_('E')
1757 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_T_FMT
)))
1759 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(T_FMT
));
1761 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1762 subfmt
= L_("%H:%M:%S");
1765 goto underlying_strftime
;
1768 subfmt
= L_("%H:%M:%S");
1776 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
1779 if (modifier
== L_('E'))
1782 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
1787 if (modifier
== L_('E'))
1790 /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
1791 is a leap year, except that YEAR and YEAR - 1 both work
1792 correctly even when (tp->tm_year + TM_YEAR_BASE) would
1794 int year
= (tp
->tm_year
1796 ? TM_YEAR_BASE
% 400
1797 : TM_YEAR_BASE
% 400 - 400));
1798 int year_adjust
= 0;
1799 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
1803 /* This ISO week belongs to the previous year. */
1805 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
- 1)),
1810 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
1814 /* This ISO week belongs to the next year. */
1824 int yy
= (tp
->tm_year
% 100 + year_adjust
) % 100;
1825 DO_YEARISH (2, false,
1828 : tp
->tm_year
< -TM_YEAR_BASE
- year_adjust
1834 DO_YEARISH (4, tp
->tm_year
< -TM_YEAR_BASE
- year_adjust
,
1835 (tp
->tm_year
+ (unsigned int) TM_YEAR_BASE
1839 DO_NUMBER (2, days
/ 7 + 1);
1844 if (modifier
== L_('E'))
1847 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
1850 if (modifier
== L_('E'))
1853 DO_NUMBER (1, tp
->tm_wday
);
1856 if (modifier
== L_('E'))
1858 #if HAVE_STRUCT_ERA_ENTRY
1859 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1862 # ifdef COMPILE_WIDE
1863 subfmt
= era
->era_wformat
;
1865 subfmt
= era
->era_format
;
1871 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1873 goto underlying_strftime
;
1876 if (modifier
== L_('O'))
1879 DO_YEARISH (4, tp
->tm_year
< -TM_YEAR_BASE
,
1880 tp
->tm_year
+ (unsigned int) TM_YEAR_BASE
);
1883 if (modifier
== L_('E'))
1885 #if HAVE_STRUCT_ERA_ENTRY
1886 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1889 int delta
= tp
->tm_year
- era
->start_date
[0];
1892 DO_NUMBER (2, (era
->offset
1893 + delta
* era
->absolute_direction
));
1895 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1897 goto underlying_strftime
;
1902 int yy
= tp
->tm_year
% 100;
1904 yy
= tp
->tm_year
< - TM_YEAR_BASE
? -yy
: yy
+ 100;
1905 DO_YEARISH (2, false, yy
);
1917 /* The zone string is always given in multibyte form. We have
1918 to convert it to wide character. */
1919 size_t w
= pad
== L_('-') || width
< 0 ? 0 : width
;
1920 char const *z
= zone
;
1922 size_t len
= __mbsrtowcs_l (p
, &z
, maxsize
- i
, &st
, loc
);
1923 if (len
== (size_t) -1)
1925 size_t incr
= len
< w
? w
: len
;
1926 if (incr
>= maxsize
- i
)
1935 size_t delta
= w
- len
;
1936 __wmemmove (p
+ delta
, p
, len
);
1937 wchar_t wc
= pad
== L_('0') || pad
== L_('+') ? L
'0' : L
' ';
1938 wmemset (p
, wc
, delta
);
1945 cpy (strlen (zone
), zone
);
1950 /* :, ::, and ::: are valid only just before 'z'.
1951 :::: etc. are rejected later. */
1952 for (colons
= 1; f
[colons
] == L_(':'); colons
++)
1954 if (f
[colons
] != L_('z'))
1957 goto do_z_conversion
;
1963 if (tp
->tm_isdst
< 0)
1972 diff
= tp
->tm_gmtoff
;
1982 /* POSIX.1 requires that local time zone information be used as
1983 though strftime called tzset. */
1984 # ifndef my_strftime
1988 *tzset_called
= true;
1994 lt
= mktime_z (tz
, <m
);
1995 if (ltm
.tm_wday
< 0 || ! localtime_rz (0, <
, >m
))
1997 diff
= tm_diff (<m
, >m
);
2001 negative_number
= diff
< 0 || (diff
== 0 && *zone
== '-');
2002 hour_diff
= diff
/ 60 / 60;
2003 min_diff
= diff
/ 60 % 60;
2004 sec_diff
= diff
% 60;
2009 DO_TZ_OFFSET (5, 0, hour_diff
* 100 + min_diff
);
2011 case 1: tz_hh_mm
: /* +hh:mm */
2012 DO_TZ_OFFSET (6, 04, hour_diff
* 100 + min_diff
);
2014 case 2: tz_hh_mm_ss
: /* +hh:mm:ss */
2015 DO_TZ_OFFSET (9, 024,
2016 hour_diff
* 10000 + min_diff
* 100 + sec_diff
);
2018 case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
2023 DO_TZ_OFFSET (3, 0, hour_diff
);
2030 case L_('\0'): /* GNU extension: % at end of format. */
2035 /* Unknown format; output the format, including the '%',
2036 since this is most likely the right thing to do if a
2037 multibyte string has been misparsed. */
2039 cpy (f
- percent
+ 1, percent
);
2045 if (p
&& maxsize
!= 0)
2049 errno
= saved_errno
;