Update.
[glibc.git] / time / strftime.c
blob040b787558424e0b217816640c5f4255a6af7990
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. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #ifdef _LIBC
24 # define HAVE_LIMITS_H 1
25 # define HAVE_MBLEN 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_TM_GMTOFF 1
29 # define HAVE_TM_ZONE 1
30 # define HAVE_TZNAME 1
31 # define HAVE_TZSET 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include <ansidecl.h>
35 # include "../locale/localeinfo.h"
36 #endif
38 #include <ctype.h>
39 #include <sys/types.h> /* Some systems define `time_t' here. */
41 #ifdef TIME_WITH_SYS_TIME
42 # include <sys/time.h>
43 # include <time.h>
44 #else
45 # ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 # else
48 # include <time.h>
49 # endif
50 #endif
51 #if HAVE_TZNAME
52 extern char *tzname[];
53 #endif
55 /* Do multibyte processing if multibytes are supported, unless
56 multibyte sequences are safe in formats. Multibyte sequences are
57 safe if they cannot contain byte sequences that look like format
58 conversion specifications. The GNU C Library uses UTF8 multibyte
59 encoding, which is safe for formats, but strftime.c can be used
60 with other C libraries that use unsafe encodings. */
61 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
63 #if DO_MULTIBYTE
64 # if HAVE_MBRLEN
65 # include <wchar.h>
66 # else
67 /* Simulate mbrlen with mblen as best we can. */
68 # define mbstate_t int
69 # define mbrlen(s, n, ps) mblen (s, n)
70 # define mbsinit(ps) (*(ps) == 0)
71 # endif
72 static const mbstate_t mbstate_zero;
73 #endif
75 #if HAVE_LIMITS_H
76 # include <limits.h>
77 #endif
79 #if STDC_HEADERS
80 # include <stddef.h>
81 # include <stdlib.h>
82 # include <string.h>
83 #else
84 # define memcpy(d, s, n) bcopy ((s), (d), (n))
85 #endif
87 #ifndef __P
88 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
89 # define __P(args) args
90 # else
91 # define __P(args) ()
92 # endif /* GCC. */
93 #endif /* Not __P. */
95 #ifndef PTR
96 # ifdef __STDC__
97 # define PTR void *
98 # else
99 # define PTR char *
100 # endif
101 #endif
103 #ifndef CHAR_BIT
104 # define CHAR_BIT 8
105 #endif
107 #ifndef NULL
108 # define NULL 0
109 #endif
111 #define TYPE_SIGNED(t) ((t) -1 < 0)
113 /* Bound on length of the string representing an integer value of type t.
114 Subtract one for the sign bit if t is signed;
115 302 / 1000 is log10 (2) rounded up;
116 add one for integer division truncation;
117 add one more for a minus sign if t is signed. */
118 #define INT_STRLEN_BOUND(t) \
119 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
121 #define TM_YEAR_BASE 1900
123 #ifndef __isleap
124 /* Nonzero if YEAR is a leap year (every 4 years,
125 except every 100th isn't, and every 400th is). */
126 # define __isleap(year) \
127 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
128 #endif
131 #ifdef _LIBC
132 # define gmtime_r __gmtime_r
133 # define localtime_r __localtime_r
134 extern int __tz_compute __P ((time_t timer, const struct tm *tm));
135 # define tzname __tzname
136 # define tzset __tzset
137 #else
138 # if ! HAVE_LOCALTIME_R
139 # if ! HAVE_TM_GMTOFF
140 /* Approximate gmtime_r as best we can in its absence. */
141 # define gmtime_r my_gmtime_r
142 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
143 static struct tm *
144 gmtime_r (t, tp)
145 const time_t *t;
146 struct tm *tp;
148 struct tm *l = gmtime (t);
149 if (! l)
150 return 0;
151 *tp = *l;
152 return tp;
154 # endif /* ! HAVE_TM_GMTOFF */
156 /* Approximate localtime_r as best we can in its absence. */
157 # define localtime_r my_localtime_r
158 static struct tm *localtime_r __P ((const time_t *, struct tm *));
159 static struct tm *
160 localtime_r (t, tp)
161 const time_t *t;
162 struct tm *tp;
164 struct tm *l = localtime (t);
165 if (! l)
166 return 0;
167 *tp = *l;
168 return tp;
170 # endif /* ! HAVE_LOCALTIME_R */
171 #endif /* ! defined (_LIBC) */
174 #if !defined (memset) && !defined (HAVE_MEMSET) && !defined (_LIBC)
175 /* Some systems lack the `memset' function and we don't want to
176 introduce additional dependencies. */
177 static const char spaces[16] = " ";
178 static const char zeroes[16] = "0000000000000000";
180 # define memset_space(P, Len) \
181 do { \
182 int _len = (Len); \
184 do \
186 int _this = _len > 16 ? 16 : _len; \
187 memcpy ((P), spaces, _this); \
188 (P) += _this; \
189 _len -= _this; \
191 while (_len > 0); \
192 } while (0)
194 # define memset_zero(P, Len) \
195 do { \
196 int _len = (Len); \
198 do \
200 int _this = _len > 16 ? 16 : _len; \
201 memcpy ((P), zeroes, _this); \
202 (P) += _this; \
203 _len -= _this; \
205 while (_len > 0); \
206 } while (0)
207 #else
208 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
209 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
210 #endif
212 #define add(n, f) \
213 do \
215 int _n = (n); \
216 int _delta = width - _n; \
217 int _incr = _n + (_delta > 0 ? _delta : 0); \
218 if (i + _incr >= maxsize) \
219 return 0; \
220 if (p) \
222 if (_delta > 0) \
224 if (pad == '0') \
225 memset_zero (p, _delta); \
226 else \
227 memset_space (p, _delta); \
229 f; \
230 p += _n; \
232 i += _incr; \
233 } while (0)
235 #define cpy(n, s) \
236 add ((n), \
237 if (to_lowcase) \
238 memcpy_lowcase (p, (s), _n); \
239 else if (to_uppcase) \
240 memcpy_uppcase (p, (s), _n); \
241 else \
242 memcpy ((PTR) p, (PTR) (s), _n))
246 #ifdef _LIBC
247 # define TOUPPER(Ch) toupper (Ch)
248 # define TOLOWER(Ch) tolower (Ch)
249 #else
250 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
251 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
252 #endif
253 /* We don't use `isdigit' here since the locale dependent
254 interpretation is not what we want here. We only need to accept
255 the arabic digits in the ASCII range. One day there is perhaps a
256 more reliable way to accept other sets of digits. */
257 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
259 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
261 static char *
262 memcpy_lowcase (dest, src, len)
263 char *dest;
264 const char *src;
265 size_t len;
267 while (len-- > 0)
268 dest[len] = TOLOWER (src[len]);
269 return dest;
272 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
274 static char *
275 memcpy_uppcase (dest, src, len)
276 char *dest;
277 const char *src;
278 size_t len;
280 while (len-- > 0)
281 dest[len] = TOUPPER (src[len]);
282 return dest;
286 #if ! HAVE_TM_GMTOFF
287 /* Yield the difference between *A and *B,
288 measured in seconds, ignoring leap seconds. */
289 static int tm_diff __P ((const struct tm *, const struct tm *));
290 static int
291 tm_diff (a, b)
292 const struct tm *a;
293 const struct tm *b;
295 /* Compute intervening leap days correctly even if year is negative.
296 Take care to avoid int overflow in leap day calculations,
297 but it's OK to assume that A and B are close to each other. */
298 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
299 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
300 int a100 = a4 / 25 - (a4 % 25 < 0);
301 int b100 = b4 / 25 - (b4 % 25 < 0);
302 int a400 = a100 >> 2;
303 int b400 = b100 >> 2;
304 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
305 int years = a->tm_year - b->tm_year;
306 int days = (365 * years + intervening_leap_days
307 + (a->tm_yday - b->tm_yday));
308 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
309 + (a->tm_min - b->tm_min))
310 + (a->tm_sec - b->tm_sec));
312 #endif /* ! HAVE_TM_GMTOFF */
316 /* The number of days from the first day of the first ISO week of this
317 year to the year day YDAY with week day WDAY. ISO weeks start on
318 Monday; the first ISO week has the year's first Thursday. YDAY may
319 be as small as YDAY_MINIMUM. */
320 #define ISO_WEEK_START_WDAY 1 /* Monday */
321 #define ISO_WEEK1_WDAY 4 /* Thursday */
322 #define YDAY_MINIMUM (-366)
323 static int iso_week_days __P ((int, int));
324 #ifdef __GNUC__
325 inline
326 #endif
327 static int
328 iso_week_days (yday, wday)
329 int yday;
330 int wday;
332 /* Add enough to the first operand of % to make it nonnegative. */
333 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
334 return (yday
335 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
336 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
340 #ifndef _NL_CURRENT
341 static char const weekday_name[][10] =
343 "Sunday", "Monday", "Tuesday", "Wednesday",
344 "Thursday", "Friday", "Saturday"
346 static char const month_name[][10] =
348 "January", "February", "March", "April", "May", "June",
349 "July", "August", "September", "October", "November", "December"
351 #endif
354 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
355 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
356 Work around this bug by copying *tp before it might be munged. */
357 size_t _strftime_copytm __P ((char *, size_t, const char *,
358 const struct tm *));
359 size_t
360 strftime (s, maxsize, format, tp)
361 char *s;
362 size_t maxsize;
363 const char *format;
364 const struct tm *tp;
366 struct tm tmcopy;
367 tmcopy = *tp;
368 return _strftime_copytm (s, maxsize, format, &tmcopy);
370 # ifdef strftime
371 # undef strftime
372 # endif
373 # define strftime(S, Maxsize, Format, Tp) \
374 _strftime_copytm (S, Maxsize, Format, Tp)
375 #endif
378 /* Write information from TP into S according to the format
379 string FORMAT, writing no more that MAXSIZE characters
380 (including the terminating '\0') and returning number of
381 characters written. If S is NULL, nothing will be written
382 anywhere, so to determine how many characters would be
383 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
384 size_t
385 strftime (s, maxsize, format, tp)
386 char *s;
387 size_t maxsize;
388 const char *format;
389 const struct tm *tp;
391 int hour12 = tp->tm_hour;
392 #ifdef _NL_CURRENT
393 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
394 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
395 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
396 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
397 const char *const ampm = _NL_CURRENT (LC_TIME,
398 hour12 > 11 ? PM_STR : AM_STR);
399 size_t aw_len = strlen (a_wkday);
400 size_t am_len = strlen (a_month);
401 size_t ap_len = strlen (ampm);
402 #else
403 const char *const f_wkday = weekday_name[tp->tm_wday];
404 const char *const f_month = month_name[tp->tm_mon];
405 const char *const a_wkday = f_wkday;
406 const char *const a_month = f_month;
407 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
408 size_t aw_len = 3;
409 size_t am_len = 3;
410 size_t ap_len = 2;
411 #endif
412 size_t wkday_len = strlen (f_wkday);
413 size_t month_len = strlen (f_month);
414 const char *zone;
415 size_t zonelen;
416 size_t i = 0;
417 char *p = s;
418 const char *f;
420 zone = NULL;
421 #if !defined _LIBC && HAVE_TM_ZONE
422 /* XXX We have some problems here. First, the string pointed to by
423 tm_zone is dynamically allocated while loading the zone data. But
424 when another zone is loaded since the information in TP were
425 computed this would be a stale pointer.
426 The second problem is the POSIX test suite which assumes setting
427 the environment variable TZ to a new value before calling strftime()
428 will influence the result (the %Z format) even if the information in
429 TP is computed with a totally different time zone. --drepper@gnu */
430 zone = (const char *) tp->tm_zone;
431 #endif
432 #if HAVE_TZNAME
433 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
434 time zone names contained in the external variable `tzname' shall
435 be set as if the tzset() function had been called. */
436 # if HAVE_TZSET
437 tzset ();
438 # endif
440 if (!(zone && *zone) && tp->tm_isdst >= 0)
441 zone = tzname[tp->tm_isdst];
442 #endif
443 if (! zone)
444 zone = ""; /* POSIX.2 requires the empty string here. */
446 zonelen = strlen (zone);
448 if (hour12 > 12)
449 hour12 -= 12;
450 else
451 if (hour12 == 0) hour12 = 12;
453 for (f = format; *f != '\0'; ++f)
455 int pad; /* Padding for number ('-', '_', or 0). */
456 int modifier; /* Field modifier ('E', 'O', or 0). */
457 int digits; /* Max digits for numeric format. */
458 int number_value; /* Numeric value to be printed. */
459 int negative_number; /* 1 if the number is negative. */
460 const char *subfmt;
461 char *bufp;
462 char buf[1 + (sizeof (int) < sizeof (time_t)
463 ? INT_STRLEN_BOUND (time_t)
464 : INT_STRLEN_BOUND (int))];
465 int width = -1;
466 int to_lowcase = 0;
467 int to_uppcase = 0;
468 int change_case = 0;
470 #if DO_MULTIBYTE
472 switch (*f)
474 case '%':
475 break;
477 case '\a': case '\b': case '\t': case '\n':
478 case '\v': case '\f': case '\r':
479 case ' ': case '!': case '"': case '#': case '&': case'\'':
480 case '(': case ')': case '*': case '+': case ',': case '-':
481 case '.': case '/': case '0': case '1': case '2': case '3':
482 case '4': case '5': case '6': case '7': case '8': case '9':
483 case ':': case ';': case '<': case '=': case '>': case '?':
484 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
485 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
486 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
487 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
488 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
489 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
490 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
491 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
492 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
493 case 'x': case 'y': case 'z': case '{': case '|': case '}':
494 case '~':
495 /* The C Standard requires these 98 characters (plus '%') to
496 be in the basic execution character set. None of these
497 characters can start a multibyte sequence, so they need
498 not be analyzed further. */
499 add (1, *p = *f);
500 continue;
502 default:
503 /* Copy this multibyte sequence until we reach its end, find
504 an error, or come back to the initial shift state. */
506 mbstate_t mbstate = mbstate_zero;
507 size_t len = 0;
511 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
513 if (bytes == 0)
514 break;
516 if (bytes == (size_t) -2 || bytes == (size_t) -1)
518 len++;
519 break;
522 len += bytes;
524 while (! mbsinit (&mbstate));
526 cpy (len, f);
527 continue;
531 #else /* ! DO_MULTIBYTE */
533 /* Either multibyte encodings are not supported, or they are
534 safe for formats, so any non-'%' byte can be copied through. */
535 if (*f != '%')
537 add (1, *p = *f);
538 continue;
541 #endif /* ! DO_MULTIBYTE */
543 /* Check for flags that can modify a format. */
544 pad = 0;
545 while (1)
547 switch (*++f)
549 /* This influences the number formats. */
550 case '_':
551 case '-':
552 case '0':
553 pad = *f;
554 continue;
556 /* This changes textual output. */
557 case '^':
558 to_uppcase = 1;
559 continue;
560 case '#':
561 change_case = 1;
562 continue;
564 default:
565 break;
567 break;
570 /* As a GNU extension we allow to specify the field width. */
571 if (ISDIGIT (*f))
573 width = 0;
576 width *= 10;
577 width += *f - '0';
578 ++f;
580 while (ISDIGIT (*f));
583 /* Check for modifiers. */
584 switch (*f)
586 case 'E':
587 case 'O':
588 modifier = *f++;
589 break;
591 default:
592 modifier = 0;
593 break;
596 /* Now do the specified format. */
597 switch (*f)
599 #define DO_NUMBER(d, v) \
600 digits = width == -1 ? d : width; \
601 number_value = v; goto do_number
602 #define DO_NUMBER_SPACEPAD(d, v) \
603 digits = width == -1 ? d : width; \
604 number_value = v; goto do_number_spacepad
606 case '%':
607 if (modifier != 0)
608 goto bad_format;
609 add (1, *p = *f);
610 break;
612 case 'a':
613 if (modifier != 0)
614 goto bad_format;
615 if (change_case)
617 to_uppcase = 1;
618 to_lowcase = 0;
620 cpy (aw_len, a_wkday);
621 break;
623 case 'A':
624 if (modifier != 0)
625 goto bad_format;
626 if (change_case)
628 to_uppcase = 1;
629 to_lowcase = 0;
631 cpy (wkday_len, f_wkday);
632 break;
634 case 'b':
635 case 'h': /* POSIX.2 extension. */
636 if (modifier != 0)
637 goto bad_format;
638 cpy (am_len, a_month);
639 break;
641 case 'B':
642 if (modifier != 0)
643 goto bad_format;
644 if (change_case)
646 to_uppcase = 1;
647 to_lowcase = 0;
649 cpy (month_len, f_month);
650 break;
652 case 'c':
653 if (modifier == 'O')
654 goto bad_format;
655 #ifdef _NL_CURRENT
656 if (! (modifier == 'E'
657 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
658 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
659 #else
660 subfmt = "%a %b %e %H:%M:%S %Y";
661 #endif
663 subformat:
665 char *old_start = p;
666 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
667 if (len == 0 && *subfmt)
668 return 0;
669 add (len, strftime (p, maxsize - i, subfmt, tp));
671 if (to_uppcase)
672 while (old_start < p)
674 *old_start = TOUPPER (*old_start);
675 ++old_start;
678 break;
680 case 'C': /* POSIX.2 extension. */
681 if (modifier == 'O')
682 goto bad_format;
683 #if HAVE_STRUCT_ERA_ENTRY
684 if (modifier == 'E')
686 struct era_entry *era = _nl_get_era_entry (tp);
687 if (era)
689 size_t len = strlen (era->name_fmt);
690 cpy (len, era->name_fmt);
691 break;
694 #endif
696 int year = tp->tm_year + TM_YEAR_BASE;
697 DO_NUMBER (1, year / 100 - (year % 100 < 0));
700 case 'x':
701 if (modifier == 'O')
702 goto bad_format;
703 #ifdef _NL_CURRENT
704 if (! (modifier == 'E'
705 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
706 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
707 goto subformat;
708 #endif
709 /* Fall through. */
710 case 'D': /* POSIX.2 extension. */
711 if (modifier != 0)
712 goto bad_format;
713 subfmt = "%m/%d/%y";
714 goto subformat;
716 case 'd':
717 if (modifier == 'E')
718 goto bad_format;
720 DO_NUMBER (2, tp->tm_mday);
722 case 'e': /* POSIX.2 extension. */
723 if (modifier == 'E')
724 goto bad_format;
726 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
728 /* All numeric formats set DIGITS and NUMBER_VALUE and then
729 jump to one of these two labels. */
731 do_number_spacepad:
732 /* Force `_' flag unless overwritten by `0' flag. */
733 if (pad != '0')
734 pad = '_';
736 do_number:
737 /* Format the number according to the MODIFIER flag. */
739 #ifdef _NL_CURRENT
740 if (modifier == 'O' && 0 <= number_value)
742 /* Get the locale specific alternate representation of
743 the number NUMBER_VALUE. If none exist NULL is returned. */
744 const char *cp = _nl_get_alt_digit (number_value);
746 if (cp != NULL)
748 size_t digitlen = strlen (cp);
749 if (digitlen != 0)
751 cpy (digitlen, cp);
752 break;
756 #endif
758 unsigned int u = number_value;
760 bufp = buf + sizeof (buf);
761 negative_number = number_value < 0;
763 if (negative_number)
764 u = -u;
767 *--bufp = u % 10 + '0';
768 while ((u /= 10) != 0);
771 do_number_sign_and_padding:
772 if (negative_number)
773 *--bufp = '-';
775 if (pad != '-')
777 int padding = digits - (buf + sizeof (buf) - bufp);
779 if (pad == '_')
781 while (0 < padding--)
782 *--bufp = ' ';
784 else
786 bufp += negative_number;
787 while (0 < padding--)
788 *--bufp = '0';
789 if (negative_number)
790 *--bufp = '-';
794 cpy (buf + sizeof (buf) - bufp, bufp);
795 break;
798 case 'H':
799 if (modifier == 'E')
800 goto bad_format;
802 DO_NUMBER (2, tp->tm_hour);
804 case 'I':
805 if (modifier == 'E')
806 goto bad_format;
808 DO_NUMBER (2, hour12);
810 case 'k': /* GNU extension. */
811 if (modifier == 'E')
812 goto bad_format;
814 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
816 case 'l': /* GNU extension. */
817 if (modifier == 'E')
818 goto bad_format;
820 DO_NUMBER_SPACEPAD (2, hour12);
822 case 'j':
823 if (modifier == 'E')
824 goto bad_format;
826 DO_NUMBER (3, 1 + tp->tm_yday);
828 case 'M':
829 if (modifier == 'E')
830 goto bad_format;
832 DO_NUMBER (2, tp->tm_min);
834 case 'm':
835 if (modifier == 'E')
836 goto bad_format;
838 DO_NUMBER (2, tp->tm_mon + 1);
840 case 'n': /* POSIX.2 extension. */
841 add (1, *p = '\n');
842 break;
844 case 'P':
845 to_lowcase = 1;
846 /* FALLTHROUGH */
848 case 'p':
849 if (change_case)
851 to_uppcase = 0;
852 to_lowcase = 1;
854 cpy (ap_len, ampm);
855 break;
857 case 'R': /* GNU extension. */
858 subfmt = "%H:%M";
859 goto subformat;
861 case 'r': /* POSIX.2 extension. */
862 #ifdef _NL_CURRENT
863 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
864 #endif
865 subfmt = "%I:%M:%S %p";
866 goto subformat;
868 case 'S':
869 if (modifier == 'E')
870 goto bad_format;
872 DO_NUMBER (2, tp->tm_sec);
874 case 's': /* GNU extension. */
876 struct tm ltm;
877 time_t t;
879 ltm = *tp;
880 t = mktime (&ltm);
882 /* Generate string value for T using time_t arithmetic;
883 this works even if sizeof (long) < sizeof (time_t). */
885 bufp = buf + sizeof (buf);
886 negative_number = t < 0;
890 int d = t % 10;
891 t /= 10;
893 if (negative_number)
895 d = -d;
897 /* Adjust if division truncates to minus infinity. */
898 if (0 < -1 % 10 && d < 0)
900 t++;
901 d += 10;
905 *--bufp = d + '0';
907 while (t != 0);
909 digits = 1;
910 goto do_number_sign_and_padding;
913 case 'X':
914 if (modifier == 'O')
915 goto bad_format;
916 #ifdef _NL_CURRENT
917 if (! (modifier == 'E'
918 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
919 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
920 goto subformat;
921 #endif
922 /* Fall through. */
923 case 'T': /* POSIX.2 extension. */
924 subfmt = "%H:%M:%S";
925 goto subformat;
927 case 't': /* POSIX.2 extension. */
928 add (1, *p = '\t');
929 break;
931 case 'u': /* POSIX.2 extension. */
932 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
934 case 'U':
935 if (modifier == 'E')
936 goto bad_format;
938 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
940 case 'V':
941 case 'g': /* GNU extension. */
942 case 'G': /* GNU extension. */
943 if (modifier == 'E')
944 goto bad_format;
946 int year = tp->tm_year + TM_YEAR_BASE;
947 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
949 if (days < 0)
951 /* This ISO week belongs to the previous year. */
952 year--;
953 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
954 tp->tm_wday);
956 else
958 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
959 tp->tm_wday);
960 if (0 <= d)
962 /* This ISO week belongs to the next year. */
963 year++;
964 days = d;
968 switch (*f)
970 case 'g':
971 DO_NUMBER (2, (year % 100 + 100) % 100);
973 case 'G':
974 DO_NUMBER (1, year);
976 default:
977 DO_NUMBER (2, days / 7 + 1);
981 case 'W':
982 if (modifier == 'E')
983 goto bad_format;
985 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
987 case 'w':
988 if (modifier == 'E')
989 goto bad_format;
991 DO_NUMBER (1, tp->tm_wday);
993 case 'Y':
994 #if HAVE_STRUCT_ERA_ENTRY
995 if (modifier == 'E')
997 struct era_entry *era = _nl_get_era_entry (tp);
998 if (era)
1000 subfmt = strchr (era->name_fmt, '\0') + 1;
1001 goto subformat;
1004 #endif
1005 if (modifier == 'O')
1006 goto bad_format;
1007 else
1008 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1010 case 'y':
1011 #if HAVE_STRUCT_ERA_ENTRY
1012 if (modifier == 'E')
1014 struct era_entry *era = _nl_get_era_entry (tp);
1015 if (era)
1017 int delta = tp->tm_year - era->start_date[0];
1018 DO_NUMBER (1, (era->offset
1019 + (era->direction == '-' ? -delta : delta)));
1022 #endif
1023 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1025 case 'Z':
1026 if (change_case)
1028 to_uppcase = 0;
1029 to_lowcase = 1;
1031 cpy (zonelen, zone);
1032 break;
1034 case 'z': /* GNU extension. */
1035 if (tp->tm_isdst < 0)
1036 break;
1039 int diff;
1040 #if HAVE_TM_GMTOFF
1041 diff = tp->tm_gmtoff;
1042 #else
1043 struct tm gtm;
1044 struct tm ltm;
1045 time_t lt;
1047 ltm = *tp;
1048 lt = mktime (&ltm);
1050 if (lt == (time_t) -1)
1052 /* mktime returns -1 for errors, but -1 is also a
1053 valid time_t value. Check whether an error really
1054 occurred. */
1055 struct tm tm;
1056 localtime_r (&lt, &tm);
1058 if ((ltm.tm_sec ^ tm.tm_sec)
1059 | (ltm.tm_min ^ tm.tm_min)
1060 | (ltm.tm_hour ^ tm.tm_hour)
1061 | (ltm.tm_mday ^ tm.tm_mday)
1062 | (ltm.tm_mon ^ tm.tm_mon)
1063 | (ltm.tm_year ^ tm.tm_year))
1064 break;
1067 if (! gmtime_r (&lt, &gtm))
1068 break;
1070 diff = tm_diff (&ltm, &gtm);
1071 #endif
1073 if (diff < 0)
1075 add (1, *p = '-');
1076 diff = -diff;
1078 else
1079 add (1, *p = '+');
1081 diff /= 60;
1082 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1085 case '\0': /* GNU extension: % at end of format. */
1086 --f;
1087 /* Fall through. */
1088 default:
1089 /* Unknown format; output the format, including the '%',
1090 since this is most likely the right thing to do if a
1091 multibyte string has been misparsed. */
1092 bad_format:
1094 int flen;
1095 for (flen = 1; f[1 - flen] != '%'; flen++)
1096 continue;
1097 cpy (flen, &f[1 - flen]);
1099 break;
1103 if (p)
1104 *p = '\0';
1105 return i;