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_STRUCT_TM_TM_GMTOFF 1
29 # define HAVE_STRUCT_TM_TM_ZONE 1
30 # include "../locale/localeinfo.h"
32 # include <libc-config.h>
34 # include "fprintftime.h"
36 # include "strftime.h"
38 # include "time-internal.h"
41 /* Whether to require GNU behavior for AM and PM indicators, even on
42 other platforms. This matters only in non-C locales.
43 The default is to require it; you can override this via
44 AC_DEFINE([REQUIRE_GNUISH_STRFTIME_AM_PM], 1) and if you do that
45 you may be able to omit Gnulib's localename module and its dependencies. */
46 #ifndef REQUIRE_GNUISH_STRFTIME_AM_PM
47 # define REQUIRE_GNUISH_STRFTIME_AM_PM true
50 # undef REQUIRE_GNUISH_STRFTIME_AM_PM
51 # define REQUIRE_GNUISH_STRFTIME_AM_PM false
62 /* Do multibyte processing if multibyte encodings are supported, unless
63 multibyte sequences are safe in formats. Multibyte sequences are
64 safe if they cannot contain byte sequences that look like format
65 conversion specifications. The multibyte encodings used by the
66 C library on the various platforms (UTF-8, GB2312, GBK, CP936,
67 GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
68 SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
69 cannot occur in a multibyte character except in the first byte.
71 The DEC-HANYU encoding used on OSF/1 is not safe for formats, but
72 this encoding has never been seen in real-life use, so we ignore
74 #if !(defined __osf__ && 0)
75 # define MULTIBYTE_IS_FORMAT_SAFE 1
77 #define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
81 static const mbstate_t mbstate_zero
;
86 #include <stdckdint.h>
91 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
92 # include "localename.h"
93 #elif defined _WIN32 && !defined __CYGWIN__
97 #include "attribute.h"
102 # define CHAR_T wchar_t
103 # define UCHAR_T unsigned int
104 # define L_(Str) L##Str
105 # define NLW(Sym) _NL_W##Sym
107 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
108 # define STRLEN(s) __wcslen (s)
112 # define UCHAR_T unsigned char
114 # define NLW(Sym) Sym
115 # define ABALTMON_1 _NL_ABALTMON_1
117 # define MEMCPY(d, s, n) memcpy (d, s, n)
118 # define STRLEN(s) strlen (s)
122 /* Shift A right by B bits portably, by dividing A by 2**B and
123 truncating towards minus infinity. A and B should be free of side
124 effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
125 INT_BITS is the number of useful bits in an int. GNU code can
126 assume that INT_BITS is at least 32.
128 ISO C99 says that A >> B is implementation-defined if A < 0. Some
129 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
130 right in the usual way when A < 0, so SHR falls back on division if
131 ordinary A >> B doesn't seem to be the usual signed shift. */
135 : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
139 ZERO_PAD
, /* (default) Pad with 0 unless format says otherwise. */
140 ALWAYS_ZERO_PAD
, /* '0' Always pad with 0. */
141 SIGN_PAD
, /* '+' Always output a sign. */
142 SPACE_PAD
, /* '_' Pad with space. */
143 NO_PAD
/* '-' Do not pad. */
146 #define TM_YEAR_BASE 1900
149 /* Nonzero if YEAR is a leap year (every 4 years,
150 except every 100th isn't, and every 400th is). */
151 # define __isleap(year) \
152 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
157 # define mktime_z(tz, tm) mktime (tm)
158 # define tzname __tzname
159 # define tzset __tzset
161 # define time_t __time64_t
162 # define __gmtime_r(t, tp) __gmtime64_r (t, tp)
163 # define mktime(tp) __mktime64 (tp)
167 # define STREAM_OR_CHAR_T FILE
168 # define STRFTIME_ARG(x) /* empty */
170 # define STREAM_OR_CHAR_T CHAR_T
171 # define STRFTIME_ARG(x) x,
175 # define memset_byte(P, Len, Byte) \
176 do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
177 # define memset_space(P, Len) memset_byte (P, Len, ' ')
178 # define memset_zero(P, Len) memset_byte (P, Len, '0')
179 #elif defined COMPILE_WIDE
180 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
181 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
183 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
184 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
188 # define advance(P, N)
190 # define advance(P, N) ((P) += (N))
193 #define add(n, f) width_add (width, n, f)
194 #define width_add(width, n, f) \
198 size_t _w = pad == NO_PAD || width < 0 ? 0 : width; \
199 size_t _incr = _n < _w ? _w : _n; \
200 if (_incr >= maxsize - i) \
209 size_t _delta = _w - _n; \
210 if (pad == ALWAYS_ZERO_PAD || pad == SIGN_PAD) \
211 memset_zero (p, _delta); \
213 memset_space (p, _delta); \
221 #define add1(c) width_add1 (width, c)
223 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
225 # define width_add1(width, c) width_add (width, 1, *p = c)
228 #define cpy(n, s) width_cpy (width, n, s)
230 # define width_cpy(width, n, s) \
231 width_add (width, n, \
235 fwrite_lowcase (p, (s), _n); \
236 else if (to_uppcase) \
237 fwrite_uppcase (p, (s), _n); \
240 /* Ignore the value of fwrite. The caller can determine whether \
241 an error occurred by inspecting ferror (P). All known fwrite \
242 implementations set the stream's error indicator when they \
243 fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do \
244 not require this. */ \
245 fwrite (s, _n, 1, p); \
251 # define width_cpy(width, n, s) \
252 width_add (width, n, \
254 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
255 else if (to_uppcase) \
256 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
258 MEMCPY ((void *) p, (void const *) (s), _n))
262 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
263 # undef __mbsrtowcs_l
264 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
269 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
270 /* We use this code also for the extended locale handling where the
271 function gets as an additional argument the locale which has to be
272 used. To access the values we have to redefine the _NL_CURRENT
274 # define strftime __strftime_l
275 # define wcsftime __wcsftime_l
277 # define _NL_CURRENT(category, item) \
278 (current->values[_NL_ITEM_INDEX (item)].string)
279 # define LOCALE_PARAM , locale_t loc
280 # define LOCALE_ARG , loc
281 # define HELPER_LOCALE_ARG , current
283 # define LOCALE_PARAM
286 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
288 # define HELPER_LOCALE_ARG
293 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
294 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
295 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
297 # define TOUPPER(Ch, L) towupper (Ch)
298 # define TOLOWER(Ch, L) towlower (Ch)
301 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
302 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
303 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
306 # define TOUPPER(Ch, L) c_toupper (Ch)
307 # define TOLOWER(Ch, L) c_tolower (Ch)
309 # define TOUPPER(Ch, L) toupper (Ch)
310 # define TOLOWER(Ch, L) tolower (Ch)
314 /* We don't use 'isdigit' here since the locale dependent
315 interpretation is not what we want here. We only need to accept
316 the arabic digits in the ASCII range. One day there is perhaps a
317 more reliable way to accept other sets of digits. */
318 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
320 /* Avoid false GCC warning "'memset' specified size 18446744073709551615 exceeds
321 maximum object size 9223372036854775807", caused by insufficient data flow
322 analysis and value propagation of the 'width_add' expansion when GCC is not
323 optimizing. Cf. <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443>. */
324 #if _GL_GNUC_PREREQ (7, 0) && !__OPTIMIZE__
325 # pragma GCC diagnostic ignored "-Wstringop-overflow"
330 fwrite_lowcase (FILE *fp
, const CHAR_T
*src
, size_t len
)
334 fputc (TOLOWER ((UCHAR_T
) *src
, loc
), fp
);
340 fwrite_uppcase (FILE *fp
, const CHAR_T
*src
, size_t len
)
344 fputc (TOUPPER ((UCHAR_T
) *src
, loc
), fp
);
349 static CHAR_T
*memcpy_lowcase (CHAR_T
*dest
, const CHAR_T
*src
,
350 size_t len LOCALE_PARAM
);
353 memcpy_lowcase (CHAR_T
*dest
, const CHAR_T
*src
, size_t len LOCALE_PARAM
)
356 dest
[len
] = TOLOWER ((UCHAR_T
) src
[len
], loc
);
360 static CHAR_T
*memcpy_uppcase (CHAR_T
*dest
, const CHAR_T
*src
,
361 size_t len LOCALE_PARAM
);
364 memcpy_uppcase (CHAR_T
*dest
, const CHAR_T
*src
, size_t len LOCALE_PARAM
)
367 dest
[len
] = TOUPPER ((UCHAR_T
) src
[len
], loc
);
373 /* Note: We assume that HAVE_STRFTIME_LZ implies HAVE_STRFTIME_L.
374 Otherwise, we would have to write (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ)
375 instead of HAVE_STRFTIME_L everywhere. */
377 /* Define to 1 if we can use the system's native functions that takes a
378 timezone_t argument. As of 2024, this is only true on NetBSD. */
379 #define HAVE_NATIVE_TIME_Z \
380 (USE_C_LOCALE && HAVE_STRFTIME_L ? HAVE_STRFTIME_LZ : HAVE_STRFTIME_Z)
382 #if USE_C_LOCALE && HAVE_STRFTIME_L
384 /* Cache for the C locale object.
385 Marked volatile so that different threads see the same value
387 static volatile locale_t c_locale_cache
;
389 /* Return the C locale object, or (locale_t) 0 with errno set
390 if it cannot be created. */
395 c_locale_cache
= newlocale (LC_ALL_MASK
, "C", (locale_t
) 0);
396 return c_locale_cache
;
401 #if HAVE_NATIVE_TIME_Z
403 /* On NetBSD a null tz has undefined behavior, so use a non-null tz.
404 Cache the UTC time zone object in a volatile variable for improved
405 thread safety. This is good enough in practice, although in theory
406 stdatomic.h should be used. */
407 static volatile timezone_t utc_timezone_cache
;
409 /* Return the UTC time zone object, or (timezone_t) 0 with errno set
410 if it cannot be created. */
414 timezone_t tz
= utc_timezone_cache
;
416 utc_timezone_cache
= tz
= tzalloc ("UTC0");
423 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
425 /* Return true if an AM/PM indicator should be removed. */
427 should_remove_ampm (void)
429 /* According to glibc's 'am_pm' attribute in the locale database, an AM/PM
430 indicator should be absent in the locales for the following languages:
431 ab an ast az be ber bg br bs ce cs csb cv da de dsb eo et eu fa fi fo fr
432 fur fy ga gl gv hr hsb ht hu hy it ka kk kl ku kv kw ky lb lg li lij ln
433 lt lv mg mhr mi mk mn ms mt nb nds nhn nl nn nr nso oc os pap pl pt ro
434 ru rw sah sc se sgs sk sl sm sr ss st su sv szl tg tk tn ts tt ug uk unm
435 uz ve wae wo xh zu */
436 const char *loc
= gl_locale_name_unsafe (LC_TIME
, "LC_TIME");
437 bool remove_ampm
= false;
443 case 'b': case 'n': case 'z':
444 if (loc
[2] == '\0' || loc
[2] == '_')
448 if (loc
[2] == 't' && (loc
[3] == '\0' || loc
[3] == '_'))
459 if (loc
[2] == '\0' || loc
[2] == '_'
460 || (loc
[2] == 'r' && (loc
[3] == '\0' || loc
[3] == '_')))
463 case 'g': case 'r': case 's':
464 if (loc
[2] == '\0' || loc
[2] == '_')
475 if (loc
[2] == '\0' || loc
[2] == '_')
479 if (loc
[2] == '\0' || loc
[2] == '_'
480 || (loc
[2] == 'b' && (loc
[3] == '\0' || loc
[3] == '_')))
491 if (loc
[2] == '\0' || loc
[2] == '_')
495 if (loc
[2] == 'b' && (loc
[3] == '\0' || loc
[3] == '_'))
505 case 'o': case 't': case 'u':
506 if (loc
[2] == '\0' || loc
[2] == '_')
516 case 'a': case 'i': case 'o': case 'r': case 'y':
517 if (loc
[2] == '\0' || loc
[2] == '_')
521 if (loc
[2] == 'r' && (loc
[3] == '\0' || loc
[3] == '_'))
531 case 'a': case 'l': case 'v':
532 if (loc
[2] == '\0' || loc
[2] == '_')
542 case 'r': case 't': case 'u': case 'y':
543 if (loc
[2] == '\0' || loc
[2] == '_')
547 if (loc
[2] == 'b' && (loc
[3] == '\0' || loc
[3] == '_'))
558 if (loc
[2] == '\0' || loc
[2] == '_')
568 case 'a': case 'k': case 'l': case 'u': case 'v': case 'w': case 'y':
569 if (loc
[2] == '\0' || loc
[2] == '_')
579 case 'b': case 'g': case 'n': case 't': case 'v':
580 if (loc
[2] == '\0' || loc
[2] == '_')
584 if (loc
[2] == 'j' && (loc
[3] == '\0' || loc
[3] == '_'))
594 case 'g': case 'i': case 'k': case 'n': case 's': case 't':
595 if (loc
[2] == '\0' || loc
[2] == '_')
599 if (loc
[2] == 'r' && (loc
[3] == '\0' || loc
[3] == '_'))
609 case 'b': case 'l': case 'n': case 'r':
610 if (loc
[2] == '\0' || loc
[2] == '_')
614 if (loc
[2] == 's' && (loc
[3] == '\0' || loc
[3] == '_'))
618 if (loc
[2] == 'n' && (loc
[3] == '\0' || loc
[3] == '_'))
622 if (loc
[2] == 'o' && (loc
[3] == '\0' || loc
[3] == '_'))
633 if (loc
[2] == '\0' || loc
[2] == '_')
644 if (loc
[2] == '\0' || loc
[2] == '_')
648 if (loc
[2] == 'p' && (loc
[3] == '\0' || loc
[3] == '_'))
658 case 'o': case 'u': case 'w':
659 if (loc
[2] == '\0' || loc
[2] == '_')
669 case 'c': case 'e': case 'k': case 'l': case 'm': case 'r': case 's':
670 case 't': case 'u': case 'v':
671 if (loc
[2] == '\0' || loc
[2] == '_')
675 if (loc
[2] == 'h' && (loc
[3] == '\0' || loc
[3] == '_'))
679 if (loc
[2] == 's' && (loc
[3] == '\0' || loc
[3] == '_'))
683 if (loc
[2] == 'l' && (loc
[3] == '\0' || loc
[3] == '_'))
693 case 'g': case 'k': case 'n': case 's': case 't':
694 if (loc
[2] == '\0' || loc
[2] == '_')
704 case 'g': case 'k': case 'z':
705 if (loc
[2] == '\0' || loc
[2] == '_')
709 if (loc
[2] == 'm'&& (loc
[3] == '\0' || loc
[3] == '_'))
720 if (loc
[2] == '\0' || loc
[2] == '_')
731 if (loc
[2] == 'e' && (loc
[3] == '\0' || loc
[3] == '_'))
735 if (loc
[2] == '\0' || loc
[2] == '_')
746 if (loc
[2] == '\0' || loc
[2] == '_')
757 if (loc
[2] == '\0' || loc
[2] == '_')
773 #if ! HAVE_STRUCT_TM_TM_GMTOFF
774 /* Yield the difference between *A and *B,
775 measured in seconds, ignoring leap seconds. */
776 # define tm_diff ftime_tm_diff
777 static int tm_diff (const struct tm
*, const struct tm
*);
779 tm_diff (const struct tm
*a
, const struct tm
*b
)
781 /* Compute intervening leap days correctly even if year is negative.
782 Take care to avoid int overflow in leap day calculations,
783 but it's OK to assume that A and B are close to each other. */
784 int a4
= SHR (a
->tm_year
, 2) + SHR (TM_YEAR_BASE
, 2) - ! (a
->tm_year
& 3);
785 int b4
= SHR (b
->tm_year
, 2) + SHR (TM_YEAR_BASE
, 2) - ! (b
->tm_year
& 3);
786 int a100
= (a4
+ (a4
< 0)) / 25 - (a4
< 0);
787 int b100
= (b4
+ (b4
< 0)) / 25 - (b4
< 0);
788 int a400
= SHR (a100
, 2);
789 int b400
= SHR (b100
, 2);
790 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
791 int years
= a
->tm_year
- b
->tm_year
;
792 int days
= (365 * years
+ intervening_leap_days
793 + (a
->tm_yday
- b
->tm_yday
));
794 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
795 + (a
->tm_min
- b
->tm_min
))
796 + (a
->tm_sec
- b
->tm_sec
));
802 /* The number of days from the first day of the first ISO week of this
803 year to the year day YDAY with week day WDAY. ISO weeks start on
804 Monday; the first ISO week has the year's first Thursday. YDAY may
805 be as small as YDAY_MINIMUM. */
806 #define ISO_WEEK_START_WDAY 1 /* Monday */
807 #define ISO_WEEK1_WDAY 4 /* Thursday */
808 #define YDAY_MINIMUM (-366)
809 static int iso_week_days (int, int);
811 iso_week_days (int yday
, int wday
)
813 /* Add enough to the first operand of % to make it nonnegative. */
814 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
816 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
817 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
821 #if !defined _NL_CURRENT && (USE_C_LOCALE && !HAVE_STRFTIME_L)
822 static CHAR_T
const c_weekday_names
[][sizeof "Wednesday"] =
824 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
825 L_("Thursday"), L_("Friday"), L_("Saturday")
827 static CHAR_T
const c_month_names
[][sizeof "September"] =
829 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
830 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
831 L_("November"), L_("December")
836 /* When compiling this file, Gnulib-using applications should #define
837 my_strftime to a symbol (typically nstrftime) to name their
838 extended strftime with extra arguments TZ and NS. */
841 # define extra_args , tz, ns
842 # define extra_args_spec , timezone_t tz, int ns
844 # if defined COMPILE_WIDE
845 # define my_strftime wcsftime
846 # define nl_get_alt_digit _nl_get_walt_digit
848 # define my_strftime strftime
849 # define nl_get_alt_digit _nl_get_alt_digit
852 # define extra_args_spec
853 /* We don't have this information in general. */
858 static size_t __strftime_internal (STREAM_OR_CHAR_T
*, STRFTIME_ARG (size_t)
859 const CHAR_T
*, const struct tm
*,
860 bool, enum pad_style
, int, bool *
861 extra_args_spec LOCALE_PARAM
);
864 && (!(USE_C_LOCALE && !HAVE_STRFTIME_L) || !HAVE_STRUCT_TM_TM_ZONE)
866 /* Make sure we're calling the actual underlying strftime.
867 In some cases, time.h contains something like
868 "#define strftime rpl_strftime". */
873 /* Assuming the time zone is TZ, store into UBUF, of size UBUFSIZE, a
874 ' ' followed by the result of calling strftime with the format
875 "%MF" where M is MODIFIER (or is omitted if !MODIFIER) and F is
876 FORMAT_CHAR, along with the time information specified by *TP.
877 Return the number of bytes stored if successful, zero otherwise. */
879 underlying_strftime (timezone_t tz
, char *ubuf
, size_t ubufsize
,
880 char modifier
, char format_char
, struct tm
const *tp
)
882 /* The relevant information is available only via the
883 underlying strftime implementation, so use that. */
887 /* The space helps distinguish strftime failure from empty
896 # if HAVE_NATIVE_TIME_Z
899 tz
= utc_timezone ();
901 return 0; /* errno is set here */
905 # if !HAVE_NATIVE_TIME_Z
906 if (tz
&& tz
!= local_tz
)
915 # if USE_C_LOCALE && HAVE_STRFTIME_L
916 locale_t locale
= c_locale ();
918 return 0; /* errno is set here */
919 # if HAVE_STRFTIME_LZ
920 len
= strftime_lz (tz
, ubuf
, ubufsize
, ufmt
, tp
, locale
);
922 len
= strftime_l (ubuf
, ubufsize
, ufmt
, tp
, locale
);
926 len
= strftime_z (tz
, ubuf
, ubufsize
, ufmt
, tp
);
928 len
= strftime (ubuf
, ubufsize
, ufmt
, tp
);
932 # if !HAVE_NATIVE_TIME_Z
933 if (tz
&& !revert_tz (tz
))
939 # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) \
940 || defined __NetBSD__ || defined __sun)
941 /* glibc < 2.31, NetBSD, Solaris */
942 if (format_char
== 'c')
944 /* The output of the strftime %c directive consists of the
945 date, the time, and the time zone. But the time zone is
946 wrong, since neither TZ nor ZONE was passed as argument.
947 Therefore, remove the the last space-delimited word.
948 In order not to accidentally remove a date or a year
949 (that contains no letter) or an AM/PM indicator (that has
950 length 2), remove that last word only if it contains a
951 letter and has length >= 3. */
953 for (space
= ubuf
+ len
- 1; *space
!= ' '; space
--)
958 if (strlen (space
+ 1) >= 3)
960 /* The last word has length >= 3. */
961 bool found_letter
= false;
963 for (p
= space
+ 1; *p
!= '\0'; p
++)
964 if ((*p
>= 'A' && *p
<= 'Z')
965 || (*p
>= 'a' && *p
<= 'z'))
972 /* The last word contains a letter. */
979 # if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
980 /* The output of the strftime %p and %r directives contains
981 an AM/PM indicator even for locales where it is not
982 suitable, such as French. Remove this indicator. */
983 if (format_char
== 'p')
985 bool found_ampm
= (len
> 1);
986 if (found_ampm
&& should_remove_ampm ())
992 else if (format_char
== 'r')
994 char last_char
= ubuf
[len
- 1];
995 bool found_ampm
= !(last_char
>= '0' && last_char
<= '9');
996 if (found_ampm
&& should_remove_ampm ())
999 for (space
= ubuf
+ len
- 1; *space
!= ' '; space
--)
1015 /* Return a time zone abbreviation for TZ. Use BUF, of size BUFSIZE,
1016 to store it if needed. If MODIFIER use the strftime format
1017 "%mZ" to format it, where m is the MODIFIER; otherwise
1018 use plain "%Z". Format an abbreviation appropriate for
1019 TP and EXTRA_ARGS_SPEC. Return the empty string on failure. */
1021 get_tm_zone (timezone_t tz
, char *ubuf
, int ubufsize
, int modifier
,
1022 struct tm
const *tp
)
1024 #if HAVE_STRUCT_TM_TM_ZONE
1025 /* The POSIX test suite assumes that setting
1026 the environment variable TZ to a new value before calling strftime()
1027 will influence the result (the %Z format) even if the information in
1028 *TP is computed with a totally different time zone.
1029 This is bogus: though POSIX allows bad behavior like this,
1030 POSIX does not require it. Do the right thing instead. */
1036 # if !HAVE_NATIVE_TIME_Z
1037 timezone_t old_tz
= tz
;
1040 old_tz
= set_tz (tz
);
1046 int zsize
= underlying_strftime (tz
, ubuf
, ubufsize
, 0, 'Z', tp
);
1048 # if !HAVE_NATIVE_TIME_Z
1049 if (!revert_tz (old_tz
))
1053 return zsize
? ubuf
+ 1 : "";
1057 /* Write information from TP into S according to the format
1058 string FORMAT, writing no more that MAXSIZE characters
1059 (including the terminating '\0') and returning number of
1060 characters written. If S is NULL, nothing will be written
1061 anywhere, so to determine how many characters would be
1062 written, use NULL for S and (size_t) -1 for MAXSIZE. */
1064 my_strftime (STREAM_OR_CHAR_T
*s
, STRFTIME_ARG (size_t maxsize
)
1065 const CHAR_T
*format
,
1066 const struct tm
*tp extra_args_spec LOCALE_PARAM
)
1068 bool tzset_called
= false;
1069 return __strftime_internal (s
, STRFTIME_ARG (maxsize
) format
, tp
, false,
1071 &tzset_called extra_args LOCALE_ARG
);
1073 libc_hidden_def (my_strftime
)
1075 /* Just like my_strftime, above, but with more parameters.
1076 UPCASE indicates that the result should be converted to upper case.
1077 YR_SPEC and WIDTH specify the padding and width for the year.
1078 *TZSET_CALLED indicates whether tzset has been called here. */
1080 __strftime_internal (STREAM_OR_CHAR_T
*s
, STRFTIME_ARG (size_t maxsize
)
1081 const CHAR_T
*format
,
1082 const struct tm
*tp
, bool upcase
,
1083 enum pad_style yr_spec
, int width
, bool *tzset_called
1084 extra_args_spec LOCALE_PARAM
)
1086 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
1087 struct __locale_data
*const current
= loc
->__locales
[LC_TIME
];
1090 size_t maxsize
= (size_t) -1;
1093 int saved_errno
= errno
;
1094 int hour12
= tp
->tm_hour
;
1096 /* We cannot make the following values variables since we must delay
1097 the evaluation of these values until really needed since some
1098 expressions might not be valid in every situation. The 'struct tm'
1099 might be generated by a strptime() call that initialized
1100 only a few elements. Dereference the pointers only if the format
1101 requires this. Then it is ok to fail if the pointers are invalid. */
1103 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
1104 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
1106 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
1107 ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
1109 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1110 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
1112 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1113 ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
1114 # define a_altmonth \
1115 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1116 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
1117 # define f_altmonth \
1118 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1119 ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
1121 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
1122 ? NLW(PM_STR) : NLW(AM_STR)))
1124 # define aw_len STRLEN (a_wkday)
1125 # define am_len STRLEN (a_month)
1126 # define aam_len STRLEN (a_altmonth)
1127 # define ap_len STRLEN (ampm)
1128 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1129 /* The English abbreviated weekday names are just the first 3 characters of the
1130 English full weekday names. */
1132 (tp->tm_wday < 0 || tp->tm_wday > 6 ? L_("?") : c_weekday_names[tp->tm_wday])
1135 (tp->tm_wday < 0 || tp->tm_wday > 6 ? L_("?") : c_weekday_names[tp->tm_wday])
1136 /* The English abbreviated month names are just the first 3 characters of the
1137 English full month names. */
1139 (tp->tm_mon < 0 || tp->tm_mon > 11 ? L_("?") : c_month_names[tp->tm_mon])
1142 (tp->tm_mon < 0 || tp->tm_mon > 11 ? L_("?") : c_month_names[tp->tm_mon])
1143 /* The English AM/PM strings happen to have the same length, namely 2. */
1144 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
1148 STREAM_OR_CHAR_T
*p
= s
;
1150 #if DO_MULTIBYTE && !defined COMPILE_WIDE
1151 const char *format_end
= NULL
;
1160 for (f
= format
; *f
!= '\0'; width
= -1, f
++)
1162 enum pad_style pad
= ZERO_PAD
;
1163 int modifier
; /* Field modifier ('E', 'O', or 0). */
1164 int digits
= 0; /* Max digits for numeric format. */
1165 int number_value
; /* Numeric value to be printed. */
1166 unsigned int u_number_value
; /* (unsigned int) number_value. */
1167 bool negative_number
; /* The number is negative. */
1168 bool always_output_a_sign
; /* +/- should always be output. */
1169 int tz_colon_mask
; /* Bitmask of where ':' should appear. */
1170 const CHAR_T
*subfmt
;
1173 + 2 /* for the two colons in a %::z or %:::z time zone */
1174 + (sizeof (int) < sizeof (time_t)
1175 ? INT_STRLEN_BOUND (time_t)
1176 : INT_STRLEN_BOUND (int))];
1177 bool to_lowcase
= false;
1178 bool to_uppcase
= upcase
;
1180 bool change_case
= false;
1184 #if DO_MULTIBYTE && !defined COMPILE_WIDE
1190 case L_('\b'): case L_('\t'): case L_('\n'):
1191 case L_('\v'): case L_('\f'): case L_('\r'):
1192 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
1193 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
1194 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
1195 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
1196 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
1197 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
1198 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
1199 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
1200 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
1201 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
1202 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
1203 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
1204 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
1205 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
1206 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
1207 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
1208 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
1209 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
1211 /* The C Standard requires these 98 characters (plus '%') to
1212 be in the basic execution character set. None of these
1213 characters can start a multibyte sequence, so they need
1214 not be analyzed further. */
1219 /* Copy this multibyte sequence until we reach its end, find
1220 an error, or come back to the initial shift state. */
1222 mbstate_t mbstate
= mbstate_zero
;
1227 format_end
= f
+ strlen (f
) + 1;
1228 fsize
= format_end
- f
;
1232 size_t bytes
= mbrlen (f
+ len
, fsize
- len
, &mbstate
);
1237 if (bytes
== (size_t) -2)
1239 len
+= strlen (f
+ len
);
1243 if (bytes
== (size_t) -1)
1251 while (! mbsinit (&mbstate
));
1259 #else /* ! DO_MULTIBYTE */
1261 /* Either multibyte encodings are not supported, they are
1262 safe for formats, so any non-'%' byte can be copied through,
1263 or this is the wide character version. */
1270 #endif /* ! DO_MULTIBYTE */
1272 char const *percent
= f
;
1274 /* Check for flags that can modify a format. */
1279 /* This influences the number formats. */
1280 case L_('_'): pad
= SPACE_PAD
; continue;
1281 case L_('-'): pad
= NO_PAD
; continue;
1282 case L_('+'): pad
= SIGN_PAD
; continue;
1283 case L_('0'): pad
= ALWAYS_ZERO_PAD
; continue;
1285 /* This changes textual output. */
1304 if (ckd_mul (&width
, width
, 10)
1305 || ckd_add (&width
, width
, *f
- L_('0')))
1309 while (ISDIGIT (*f
));
1312 /* Check for modifiers. */
1325 /* Now do the specified format. */
1327 switch (format_char
)
1329 #define DO_NUMBER(d, v) \
1337 #define DO_SIGNED_NUMBER(d, negative, v) \
1338 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
1339 #define DO_YEARISH(d, negative, v) \
1340 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
1341 #define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
1345 negative_number = negative; \
1346 u_number_value = v; \
1351 /* The mask is not what you might think.
1352 When the ordinal i'th bit is set, insert a colon
1353 before the i'th digit of the time zone representation. */
1354 #define DO_TZ_OFFSET(d, mask, v) \
1358 tz_colon_mask = mask; \
1359 u_number_value = v; \
1360 goto do_tz_offset; \
1363 #define DO_NUMBER_SPACEPAD(d, v) \
1368 goto do_number_spacepad; \
1373 if (f
- 1 != percent
)
1386 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1387 cpy (aw_len
, a_wkday
);
1390 goto underlying_strftime
;
1401 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1402 cpy (STRLEN (f_wkday
), f_wkday
);
1405 goto underlying_strftime
;
1415 if (modifier
== L_('E'))
1418 if (modifier
== L_('O'))
1419 cpy (aam_len
, a_altmonth
);
1421 cpy (am_len
, a_month
);
1423 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1424 cpy (am_len
, a_month
);
1427 # if defined _WIN32 && !defined __CYGWIN__
1428 format_char
= L_('b');
1430 goto underlying_strftime
;
1434 if (modifier
== L_('E'))
1442 if (modifier
== L_('O'))
1443 cpy (STRLEN (f_altmonth
), f_altmonth
);
1445 cpy (STRLEN (f_month
), f_month
);
1447 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1448 cpy (STRLEN (f_month
), f_month
);
1451 goto underlying_strftime
;
1455 if (modifier
== L_('O'))
1458 if (! (modifier
== L_('E')
1460 (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
1463 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_T_FMT
));
1464 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1465 subfmt
= L_("%a %b %e %H:%M:%S %Y");
1466 #elif defined _WIN32 && !defined __CYGWIN__
1467 /* On native Windows, "%c" is "%d/%m/%Y %H:%M:%S" by default. */
1469 /* This code is equivalent to is_c_locale = !hard_locale (LC_TIME). */
1470 # if defined _MSC_VER
1471 const wchar_t *locale
= _wsetlocale (LC_TIME
, NULL
);
1473 (wcscmp (locale
, L
"C") == 0 || wcscmp (locale
, L
"POSIX") == 0);
1475 const char *locale
= setlocale (LC_TIME
, NULL
);
1477 (strcmp (locale
, "C") == 0 || strcmp (locale
, "POSIX") == 0);
1480 subfmt
= L_("%a %b %e %H:%M:%S %Y");
1482 subfmt
= L_("%a %e %b %Y %H:%M:%S");
1484 goto underlying_strftime
;
1491 size_t len
= __strftime_internal (NULL
, STRFTIME_ARG ((size_t) -1)
1492 subfmt
, tp
, to_uppcase
,
1493 pad
, subwidth
, tzset_called
1494 extra_args LOCALE_ARG
);
1495 add (len
, __strftime_internal (p
,
1496 STRFTIME_ARG (maxsize
- i
)
1497 subfmt
, tp
, to_uppcase
,
1498 pad
, subwidth
, tzset_called
1499 extra_args LOCALE_ARG
));
1503 #if !defined _LIBC && !(USE_C_LOCALE && !HAVE_STRFTIME_L)
1504 underlying_strftime
:
1506 char ubuf
[1024]; /* enough for any single format in practice */
1508 len
= underlying_strftime (tz
, ubuf
, sizeof ubuf
,
1509 modifier
, format_char
, tp
);
1512 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) || defined __NetBSD__ || defined __sun /* glibc < 2.31, NetBSD, Solaris */
1513 if (format_char
== L_('c'))
1515 /* The output of the strftime %c directive consists of the
1516 date, the time, and the time zone. But the time zone is
1517 wrong, since neither TZ nor ZONE was passed as argument.
1518 Therefore, remove the the last space-delimited word.
1519 In order not to accidentally remove a date or a year
1520 (that contains no letter) or an AM/PM indicator (that has
1521 length 2), remove that last word only if it contains a
1522 letter and has length >= 3. */
1524 for (space
= ubuf
+ len
- 1; *space
!= ' '; space
--)
1528 /* Found a space. */
1529 if (strlen (space
+ 1) >= 3)
1531 /* The last word has length >= 3. */
1532 bool found_letter
= false;
1534 for (p
= space
+ 1; *p
!= '\0'; p
++)
1535 if ((*p
>= 'A' && *p
<= 'Z')
1536 || (*p
>= 'a' && *p
<= 'z'))
1538 found_letter
= true;
1543 /* The last word contains a letter. */
1550 # if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
1551 /* The output of the strftime %p and %r directives contains
1552 an AM/PM indicator even for locales where it is not
1553 suitable, such as French. Remove this indicator. */
1554 else if (format_char
== L_('p'))
1556 bool found_ampm
= (len
> 1);
1557 if (found_ampm
&& should_remove_ampm ())
1563 else if (format_char
== L_('r'))
1565 char last_char
= ubuf
[len
- 1];
1566 bool found_ampm
= !(last_char
>= '0' && last_char
<= '9');
1567 if (found_ampm
&& should_remove_ampm ())
1570 for (space
= ubuf
+ len
- 1; *space
!= ' '; space
--)
1581 cpy (len
- 1, ubuf
+ 1);
1588 if (modifier
== L_('E'))
1590 #if HAVE_STRUCT_ERA_ENTRY
1591 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1594 # ifdef COMPILE_WIDE
1595 size_t len
= __wcslen (era
->era_wname
);
1596 cpy (len
, era
->era_wname
);
1598 size_t len
= strlen (era
->era_name
);
1599 cpy (len
, era
->era_name
);
1603 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1605 goto underlying_strftime
;
1610 bool negative_year
= tp
->tm_year
< - TM_YEAR_BASE
;
1611 bool zero_thru_1899
= !negative_year
& (tp
->tm_year
< 0);
1612 int century
= ((tp
->tm_year
- 99 * zero_thru_1899
) / 100
1613 + TM_YEAR_BASE
/ 100);
1614 DO_YEARISH (2, negative_year
, century
);
1618 if (modifier
== L_('O'))
1621 if (! (modifier
== L_('E')
1623 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_D_FMT
)))
1625 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_FMT
));
1627 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1628 subfmt
= L_("%m/%d/%y");
1631 goto underlying_strftime
;
1636 subfmt
= L_("%m/%d/%y");
1640 if (modifier
== L_('E'))
1643 DO_NUMBER (2, tp
->tm_mday
);
1646 if (modifier
== L_('E'))
1649 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
1651 /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
1652 and then jump to one of these labels. */
1655 always_output_a_sign
= true;
1656 goto do_number_body
;
1659 if (pad
== ZERO_PAD
)
1661 always_output_a_sign
1663 && ((digits
== 2 ? 99 : 9999) < u_number_value
1664 || digits
< width
));
1665 goto do_maybe_signed_number
;
1668 if (pad
== ZERO_PAD
)
1672 /* Format NUMBER_VALUE according to the MODIFIER flag. */
1673 negative_number
= number_value
< 0;
1674 u_number_value
= number_value
;
1677 always_output_a_sign
= false;
1679 do_maybe_signed_number
:
1683 /* Format U_NUMBER_VALUE according to the MODIFIER flag.
1684 NEGATIVE_NUMBER is nonzero if the original number was
1685 negative; in this case it was converted directly to
1686 unsigned int (i.e., modulo (UINT_MAX + 1)) without
1688 if (modifier
== L_('O') && !negative_number
)
1691 /* Get the locale specific alternate representation of
1692 the number. If none exist NULL is returned. */
1693 const CHAR_T
*cp
= nl_get_alt_digit (u_number_value
1698 size_t digitlen
= STRLEN (cp
);
1705 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1707 goto underlying_strftime
;
1711 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1713 if (negative_number
)
1714 u_number_value
= - u_number_value
;
1718 if (tz_colon_mask
& 1)
1720 tz_colon_mask
>>= 1;
1721 *--bufp
= u_number_value
% 10 + L_('0');
1722 u_number_value
/= 10;
1724 while (u_number_value
!= 0 || tz_colon_mask
!= 0);
1726 do_number_sign_and_padding
:
1727 if (pad
== ZERO_PAD
)
1728 pad
= ALWAYS_ZERO_PAD
;
1733 CHAR_T sign_char
= (negative_number
? L_('-')
1734 : always_output_a_sign
? L_('+')
1736 int numlen
= buf
+ sizeof buf
/ sizeof buf
[0] - bufp
;
1737 int shortage
= width
- !!sign_char
- numlen
;
1738 int padding
= pad
== NO_PAD
|| shortage
<= 0 ? 0 : shortage
;
1742 if (pad
== SPACE_PAD
)
1745 memset_space (p
, padding
);
1749 width_add1 (0, sign_char
);
1760 if (pad
== ZERO_PAD
&& width
< 0)
1767 subwidth
= width
- 6;
1771 subfmt
= L_("%Y-%m-%d");
1772 goto subformat_width
;
1775 if (modifier
== L_('E'))
1778 DO_NUMBER (2, tp
->tm_hour
);
1781 if (modifier
== L_('E'))
1784 DO_NUMBER (2, hour12
);
1786 case L_('k'): /* GNU extension. */
1787 if (modifier
== L_('E'))
1790 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
1792 case L_('l'): /* GNU extension. */
1793 if (modifier
== L_('E'))
1796 DO_NUMBER_SPACEPAD (2, hour12
);
1799 if (modifier
== L_('E'))
1802 DO_SIGNED_NUMBER (3, tp
->tm_yday
< -1, tp
->tm_yday
+ 1U);
1805 if (modifier
== L_('E'))
1808 DO_NUMBER (2, tp
->tm_min
);
1811 if (modifier
== L_('E'))
1814 DO_SIGNED_NUMBER (2, tp
->tm_mon
< -1, tp
->tm_mon
+ 1U);
1817 case L_('N'): /* GNU extension. */
1818 if (modifier
== L_('E'))
1821 int n
= ns
, ns_digits
= 9;
1824 int ndigs
= ns_digits
;
1825 while (width
< ndigs
|| (1 < ndigs
&& n
% 10 == 0))
1827 for (int j
= ndigs
; 0 < j
; j
--)
1828 buf
[j
- 1] = n
% 10 + L_('0'), n
/= 10;
1829 if (pad
== ZERO_PAD
)
1830 pad
= ALWAYS_ZERO_PAD
;
1831 width_cpy (0, ndigs
, buf
);
1832 width_add (width
- ndigs
, 0, (void) 0);
1844 format_char
= L_('p');
1853 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1857 goto underlying_strftime
;
1860 case L_('q'): /* GNU extension. */
1861 DO_SIGNED_NUMBER (1, false, ((tp
->tm_mon
* 11) >> 5) + 1);
1864 subfmt
= L_("%H:%M");
1869 if (*(subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
1872 subfmt
= L_("%I:%M:%S %p");
1874 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1875 subfmt
= L_("%I:%M:%S %p");
1877 #elif ((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ \
1878 || (defined _WIN32 && !defined __CYGWIN__))
1879 /* macOS, FreeBSD, native Windows strftime() may produce empty output
1881 subfmt
= L_("%I:%M:%S %p");
1884 goto underlying_strftime
;
1888 if (modifier
== L_('E'))
1891 DO_NUMBER (2, tp
->tm_sec
);
1893 case L_('s'): /* GNU extension. */
1900 t
= mktime_z (tz
, <m
);
1901 if (ltm
.tm_yday
< 0)
1907 /* Generate string value for T using time_t arithmetic;
1908 this works even if sizeof (long) < sizeof (time_t). */
1910 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1911 negative_number
= t
< 0;
1917 *--bufp
= (negative_number
? -d
: d
) + L_('0');
1922 always_output_a_sign
= false;
1923 goto do_number_sign_and_padding
;
1927 if (modifier
== L_('O'))
1930 if (! (modifier
== L_('E')
1932 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_T_FMT
)))
1934 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(T_FMT
));
1936 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1937 subfmt
= L_("%H:%M:%S");
1940 goto underlying_strftime
;
1943 subfmt
= L_("%H:%M:%S");
1951 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
1954 if (modifier
== L_('E'))
1957 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
1962 if (modifier
== L_('E'))
1965 /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
1966 is a leap year, except that YEAR and YEAR - 1 both work
1967 correctly even when (tp->tm_year + TM_YEAR_BASE) would
1969 int year
= (tp
->tm_year
1971 ? TM_YEAR_BASE
% 400
1972 : TM_YEAR_BASE
% 400 - 400));
1973 int year_adjust
= 0;
1974 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
1978 /* This ISO week belongs to the previous year. */
1980 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
- 1)),
1985 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
1989 /* This ISO week belongs to the next year. */
1999 int yy
= (tp
->tm_year
% 100 + year_adjust
) % 100;
2000 DO_YEARISH (2, false,
2003 : tp
->tm_year
< -TM_YEAR_BASE
- year_adjust
2009 DO_YEARISH (4, tp
->tm_year
< -TM_YEAR_BASE
- year_adjust
,
2010 (tp
->tm_year
+ (unsigned int) TM_YEAR_BASE
2014 DO_NUMBER (2, days
/ 7 + 1);
2019 if (modifier
== L_('E'))
2022 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
2025 if (modifier
== L_('E'))
2028 DO_NUMBER (1, tp
->tm_wday
);
2031 if (modifier
== L_('E'))
2033 #if HAVE_STRUCT_ERA_ENTRY
2034 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
2037 # ifdef COMPILE_WIDE
2038 subfmt
= era
->era_wformat
;
2040 subfmt
= era
->era_format
;
2042 if (pad
== ZERO_PAD
)
2046 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
2048 goto underlying_strftime
;
2051 if (modifier
== L_('O'))
2054 DO_YEARISH (4, tp
->tm_year
< -TM_YEAR_BASE
,
2055 tp
->tm_year
+ (unsigned int) TM_YEAR_BASE
);
2058 if (modifier
== L_('E'))
2060 #if HAVE_STRUCT_ERA_ENTRY
2061 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
2064 int delta
= tp
->tm_year
- era
->start_date
[0];
2065 if (pad
== ZERO_PAD
)
2067 DO_NUMBER (2, (era
->offset
2068 + delta
* era
->absolute_direction
));
2070 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
2072 goto underlying_strftime
;
2077 int yy
= tp
->tm_year
% 100;
2079 yy
= tp
->tm_year
< - TM_YEAR_BASE
? -yy
: yy
+ 100;
2080 DO_YEARISH (2, false, yy
);
2094 /* The tzset() call might have changed the value. */
2095 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
2097 /* POSIX.1 requires that local time zone information be used as
2098 though strftime called tzset. */
2102 *tzset_called
= true;
2104 zone
= tp
->tm_isdst
<= 1 ? tzname
[tp
->tm_isdst
] : "?";
2109 char zonebuf
[128]; /* Enough for any time zone abbreviation. */
2110 zone
= get_tm_zone (tz
, zonebuf
, sizeof zonebuf
, modifier
, tp
);
2114 /* The zone string is always given in multibyte form. We have
2115 to convert it to wide character. */
2116 size_t w
= pad
== NO_PAD
|| width
< 0 ? 0 : width
;
2117 char const *z
= zone
;
2119 size_t len
= __mbsrtowcs_l (p
, &z
, maxsize
- i
, &st
, loc
);
2120 if (len
== (size_t) -1)
2122 size_t incr
= len
< w
? w
: len
;
2123 if (incr
>= maxsize
- i
)
2132 size_t delta
= w
- len
;
2133 __wmemmove (p
+ delta
, p
, len
);
2134 wchar_t wc
= (pad
== ALWAYS_ZERO_PAD
|| pad
== SIGN_PAD
2136 wmemset (p
, wc
, delta
);
2142 cpy (strlen (zone
), zone
);
2148 /* :, ::, and ::: are valid only just before 'z'.
2149 :::: etc. are rejected later. */
2150 for (colons
= 1; f
[colons
] == L_(':'); colons
++)
2152 if (f
[colons
] != L_('z'))
2155 goto do_z_conversion
;
2161 if (tp
->tm_isdst
< 0)
2169 #if HAVE_STRUCT_TM_TM_GMTOFF
2170 diff
= tp
->tm_gmtoff
;
2182 lt
= mktime_z (tz
, <m
);
2183 if (ltm
.tm_wday
< 0 || ! localtime_rz (0, <
, >m
))
2185 diff
= tm_diff (<m
, >m
);
2189 negative_number
= diff
< 0;
2192 char zonebuf
[128]; /* Enough for any time zone abbreviation. */
2193 negative_number
= (*get_tm_zone (tz
, zonebuf
, sizeof zonebuf
,
2197 hour_diff
= diff
/ 60 / 60;
2198 min_diff
= diff
/ 60 % 60;
2199 sec_diff
= diff
% 60;
2204 DO_TZ_OFFSET (5, 0, hour_diff
* 100 + min_diff
);
2206 case 1: tz_hh_mm
: /* +hh:mm */
2207 DO_TZ_OFFSET (6, 04, hour_diff
* 100 + min_diff
);
2209 case 2: tz_hh_mm_ss
: /* +hh:mm:ss */
2210 DO_TZ_OFFSET (9, 024,
2211 hour_diff
* 10000 + min_diff
* 100 + sec_diff
);
2213 case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
2218 DO_TZ_OFFSET (3, 0, hour_diff
);
2225 case L_('\0'): /* GNU extension: % at end of format. */
2230 /* Unknown format; output the format, including the '%',
2231 since this is most likely the right thing to do if a
2232 multibyte string has been misparsed. */
2234 cpy (f
- percent
+ 1, percent
);
2240 if (p
&& maxsize
!= 0)
2244 errno
= saved_errno
;