Update.
[glibc.git] / time / strftime.c
blob898bd6c98c5f878cbc4d522f61c4da3bcfc8626f
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] = " ";
179 # define memset_space(P, Len) \
180 do { \
181 int _len = (Len); \
183 do \
185 int _this = _len > 16 ? 16 : _len; \
186 memcpy ((P), spaces, _this); \
187 (P) += _this; \
188 _len -= _this; \
190 while (_len > 0); \
191 } while (0)
192 #else
193 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
194 #endif
196 #define add(n, f) \
197 do \
199 int _n = (n); \
200 int _delta = width - _n; \
201 int _incr = _n + (_delta > 0 ? _delta : 0); \
202 if (i + _incr >= maxsize) \
203 return 0; \
204 if (p) \
206 if (_delta > 0) \
207 memset_space (p, _delta); \
208 f; \
209 p += _n; \
211 i += _incr; \
212 } while (0)
214 #define cpy(n, s) \
215 add ((n), \
216 if (to_lowcase) \
217 memcpy_lowcase (p, (s), _n); \
218 else if (to_uppcase) \
219 memcpy_uppcase (p, (s), _n); \
220 else \
221 memcpy ((PTR) p, (PTR) (s), _n))
225 #ifdef _LIBC
226 # define TOUPPER(Ch) toupper (Ch)
227 # define TOLOWER(Ch) tolower (Ch)
228 #else
229 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
230 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
231 #endif
232 /* We don't use `isdigit' here since the locale dependent
233 interpretation is not what we want here. We only need to accept
234 the arabic digits in the ASCII range. One day there is perhaps a
235 more reliable way to accept other sets of digits. */
236 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
238 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
240 static char *
241 memcpy_lowcase (dest, src, len)
242 char *dest;
243 const char *src;
244 size_t len;
246 while (len-- > 0)
247 dest[len] = TOLOWER (src[len]);
248 return dest;
251 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
253 static char *
254 memcpy_uppcase (dest, src, len)
255 char *dest;
256 const char *src;
257 size_t len;
259 while (len-- > 0)
260 dest[len] = TOUPPER (src[len]);
261 return dest;
264 #if ! HAVE_TM_GMTOFF
265 /* Yield the difference between *A and *B,
266 measured in seconds, ignoring leap seconds. */
267 static int tm_diff __P ((const struct tm *, const struct tm *));
268 static int
269 tm_diff (a, b)
270 const struct tm *a;
271 const struct tm *b;
273 /* Compute intervening leap days correctly even if year is negative.
274 Take care to avoid int overflow in leap day calculations,
275 but it's OK to assume that A and B are close to each other. */
276 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
277 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
278 int a100 = a4 / 25 - (a4 % 25 < 0);
279 int b100 = b4 / 25 - (b4 % 25 < 0);
280 int a400 = a100 >> 2;
281 int b400 = b100 >> 2;
282 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
283 int years = a->tm_year - b->tm_year;
284 int days = (365 * years + intervening_leap_days
285 + (a->tm_yday - b->tm_yday));
286 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
287 + (a->tm_min - b->tm_min))
288 + (a->tm_sec - b->tm_sec));
290 #endif /* ! HAVE_TM_GMTOFF */
294 /* The number of days from the first day of the first ISO week of this
295 year to the year day YDAY with week day WDAY. ISO weeks start on
296 Monday; the first ISO week has the year's first Thursday. YDAY may
297 be as small as YDAY_MINIMUM. */
298 #define ISO_WEEK_START_WDAY 1 /* Monday */
299 #define ISO_WEEK1_WDAY 4 /* Thursday */
300 #define YDAY_MINIMUM (-366)
301 static int iso_week_days __P ((int, int));
302 #ifdef __GNUC__
303 inline
304 #endif
305 static int
306 iso_week_days (yday, wday)
307 int yday;
308 int wday;
310 /* Add enough to the first operand of % to make it nonnegative. */
311 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
312 return (yday
313 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
314 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
318 #ifndef _NL_CURRENT
319 static char const weekday_name[][10] =
321 "Sunday", "Monday", "Tuesday", "Wednesday",
322 "Thursday", "Friday", "Saturday"
324 static char const month_name[][10] =
326 "January", "February", "March", "April", "May", "June",
327 "July", "August", "September", "October", "November", "December"
329 #endif
332 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
333 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
334 Work around this bug by copying *tp before it might be munged. */
335 size_t _strftime_copytm __P ((char *, size_t, const char *,
336 const struct tm *));
337 size_t
338 strftime (s, maxsize, format, tp)
339 char *s;
340 size_t maxsize;
341 const char *format;
342 const struct tm *tp;
344 struct tm tmcopy;
345 tmcopy = *tp;
346 return _strftime_copytm (s, maxsize, format, &tmcopy);
348 # ifdef strftime
349 # undef strftime
350 # endif
351 # define strftime(S, Maxsize, Format, Tp) \
352 _strftime_copytm (S, Maxsize, Format, Tp)
353 #endif
356 /* Write information from TP into S according to the format
357 string FORMAT, writing no more that MAXSIZE characters
358 (including the terminating '\0') and returning number of
359 characters written. If S is NULL, nothing will be written
360 anywhere, so to determine how many characters would be
361 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
362 size_t
363 strftime (s, maxsize, format, tp)
364 char *s;
365 size_t maxsize;
366 const char *format;
367 const struct tm *tp;
369 int hour12 = tp->tm_hour;
370 #ifdef _NL_CURRENT
371 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
372 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
373 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
374 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
375 const char *const ampm = _NL_CURRENT (LC_TIME,
376 hour12 > 11 ? PM_STR : AM_STR);
377 size_t aw_len = strlen (a_wkday);
378 size_t am_len = strlen (a_month);
379 size_t ap_len = strlen (ampm);
380 #else
381 const char *const f_wkday = weekday_name[tp->tm_wday];
382 const char *const f_month = month_name[tp->tm_mon];
383 const char *const a_wkday = f_wkday;
384 const char *const a_month = f_month;
385 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
386 size_t aw_len = 3;
387 size_t am_len = 3;
388 size_t ap_len = 2;
389 #endif
390 size_t wkday_len = strlen (f_wkday);
391 size_t month_len = strlen (f_month);
392 const char *zone;
393 size_t zonelen;
394 size_t i = 0;
395 char *p = s;
396 const char *f;
398 zone = NULL;
399 #if !defined _LIBC && HAVE_TM_ZONE
400 /* XXX We have some problems here. First, the string pointed to by
401 tm_zone is dynamically allocated while loading the zone data. But
402 when another zone is loaded since the information in TP were
403 computed this would be a stale pointer.
404 The second problem is the POSIX test suite which assumes setting
405 the environment variable TZ to a new value before calling strftime()
406 will influence the result (the %Z format) even if the information in
407 TP is computed with a totally different time zone. --drepper@gnu */
408 zone = (const char *) tp->tm_zone;
409 #endif
410 #if HAVE_TZNAME
411 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
412 time zone names contained in the external variable `tzname' shall
413 be set as if the tzset() function had been called. */
414 # if HAVE_TZSET
415 tzset ();
416 # endif
418 if (!(zone && *zone) && tp->tm_isdst >= 0)
419 zone = tzname[tp->tm_isdst];
420 #endif
421 if (! zone)
422 zone = ""; /* POSIX.2 requires the empty string here. */
424 zonelen = strlen (zone);
426 if (hour12 > 12)
427 hour12 -= 12;
428 else
429 if (hour12 == 0) hour12 = 12;
431 for (f = format; *f != '\0'; ++f)
433 int pad; /* Padding for number ('-', '_', or 0). */
434 int modifier; /* Field modifier ('E', 'O', or 0). */
435 int digits; /* Max digits for numeric format. */
436 int number_value; /* Numeric value to be printed. */
437 int negative_number; /* 1 if the number is negative. */
438 const char *subfmt;
439 char *bufp;
440 char buf[1 + (sizeof (int) < sizeof (time_t)
441 ? INT_STRLEN_BOUND (time_t)
442 : INT_STRLEN_BOUND (int))];
443 int width = -1;
444 int to_lowcase = 0;
445 int to_uppcase = 0;
447 #if DO_MULTIBYTE
449 switch (*f)
451 case '%':
452 break;
454 case '\a': case '\b': case '\t': case '\n':
455 case '\v': case '\f': case '\r':
456 case ' ': case '!': case '"': case '#': case '&': case'\'':
457 case '(': case ')': case '*': case '+': case ',': case '-':
458 case '.': case '/': case '0': case '1': case '2': case '3':
459 case '4': case '5': case '6': case '7': case '8': case '9':
460 case ':': case ';': case '<': case '=': case '>': case '?':
461 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
462 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
463 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
464 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
465 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
466 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
467 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
468 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
469 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
470 case 'x': case 'y': case 'z': case '{': case '|': case '}':
471 case '~':
472 /* The C Standard requires these 98 characters (plus '%') to
473 be in the basic execution character set. None of these
474 characters can start a multibyte sequence, so they need
475 not be analyzed further. */
476 add (1, *p = *f);
477 continue;
479 default:
480 /* Copy this multibyte sequence until we reach its end, find
481 an error, or come back to the initial shift state. */
483 mbstate_t mbstate = mbstate_zero;
484 size_t len = 0;
488 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
490 if (bytes == 0)
491 break;
493 if (bytes == (size_t) -2 || bytes == (size_t) -1)
495 len++;
496 break;
499 len += bytes;
501 while (! mbsinit (&mbstate));
503 cpy (len, f);
504 continue;
508 #else /* ! DO_MULTIBYTE */
510 /* Either multibyte encodings are not supported, or they are
511 safe for formats, so any non-'%' byte can be copied through. */
512 if (*f != '%')
514 add (1, *p = *f);
515 continue;
518 #endif /* ! DO_MULTIBYTE */
520 /* Check for flags that can modify a format. */
521 pad = 0;
522 while (1)
524 switch (*++f)
526 /* This influences the number formats. */
527 case '_':
528 case '-':
529 case '0':
530 pad = *f;
531 continue;
533 /* This changes textual output. */
534 case '^':
535 to_uppcase = 1;
536 continue;
538 default:
539 break;
541 break;
544 /* As a GNU extension we allow to specify the field width. */
545 if (ISDIGIT (*f))
547 width = 0;
550 width *= 10;
551 width += *f - '0';
552 ++f;
554 while (ISDIGIT (*f));
557 /* Check for modifiers. */
558 switch (*f)
560 case 'E':
561 case 'O':
562 modifier = *f++;
563 break;
565 default:
566 modifier = 0;
567 break;
570 /* Now do the specified format. */
571 switch (*f)
573 #define DO_NUMBER(d, v) \
574 digits = d; number_value = v; goto do_number
575 #define DO_NUMBER_SPACEPAD(d, v) \
576 digits = d; number_value = v; goto do_number_spacepad
578 case '%':
579 if (modifier != 0)
580 goto bad_format;
581 add (1, *p = *f);
582 break;
584 case 'a':
585 if (modifier != 0)
586 goto bad_format;
587 cpy (aw_len, a_wkday);
588 break;
590 case 'A':
591 if (modifier != 0)
592 goto bad_format;
593 cpy (wkday_len, f_wkday);
594 break;
596 case 'b':
597 case 'h': /* POSIX.2 extension. */
598 if (modifier != 0)
599 goto bad_format;
600 cpy (am_len, a_month);
601 break;
603 case 'B':
604 if (modifier != 0)
605 goto bad_format;
606 cpy (month_len, f_month);
607 break;
609 case 'c':
610 if (modifier == 'O')
611 goto bad_format;
612 #ifdef _NL_CURRENT
613 if (! (modifier == 'E'
614 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
615 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
616 #else
617 subfmt = "%a %b %e %H:%M:%S %Y";
618 #endif
620 subformat:
622 char *old_start = p;
623 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
624 if (len == 0 && *subfmt)
625 return 0;
626 add (len, strftime (p, maxsize - i, subfmt, tp));
628 if (to_uppcase)
629 while (old_start < p)
631 *old_start = TOUPPER (*old_start);
632 ++old_start;
635 break;
637 case 'C': /* POSIX.2 extension. */
638 if (modifier == 'O')
639 goto bad_format;
640 #if HAVE_STRUCT_ERA_ENTRY
641 if (modifier == 'E')
643 struct era_entry *era = _nl_get_era_entry (tp);
644 if (era)
646 size_t len = strlen (era->name_fmt);
647 cpy (len, era->name_fmt);
648 break;
651 #endif
653 int year = tp->tm_year + TM_YEAR_BASE;
654 DO_NUMBER (1, year / 100 - (year % 100 < 0));
657 case 'x':
658 if (modifier == 'O')
659 goto bad_format;
660 #ifdef _NL_CURRENT
661 if (! (modifier == 'E'
662 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
663 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
664 goto subformat;
665 #endif
666 /* Fall through. */
667 case 'D': /* POSIX.2 extension. */
668 if (modifier != 0)
669 goto bad_format;
670 subfmt = "%m/%d/%y";
671 goto subformat;
673 case 'd':
674 if (modifier == 'E')
675 goto bad_format;
677 DO_NUMBER (2, tp->tm_mday);
679 case 'e': /* POSIX.2 extension. */
680 if (modifier == 'E')
681 goto bad_format;
683 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
685 /* All numeric formats set DIGITS and NUMBER_VALUE and then
686 jump to one of these two labels. */
688 do_number_spacepad:
689 /* Force `_' flag unless overwritten by `0' flag. */
690 if (pad != '0')
691 pad = '_';
693 do_number:
694 /* Format the number according to the MODIFIER flag. */
696 #ifdef _NL_CURRENT
697 if (modifier == 'O' && 0 <= number_value)
699 /* Get the locale specific alternate representation of
700 the number NUMBER_VALUE. If none exist NULL is returned. */
701 const char *cp = _nl_get_alt_digit (number_value);
703 if (cp != NULL)
705 size_t digitlen = strlen (cp);
706 if (digitlen != 0)
708 cpy (digitlen, cp);
709 break;
713 #endif
715 unsigned int u = number_value;
717 bufp = buf + sizeof (buf);
718 negative_number = number_value < 0;
720 if (negative_number)
721 u = -u;
724 *--bufp = u % 10 + '0';
725 while ((u /= 10) != 0);
728 do_number_sign_and_padding:
729 if (negative_number)
730 *--bufp = '-';
732 if (pad != '-')
734 int padding = digits - (buf + sizeof (buf) - bufp);
736 if (pad == '_')
738 while (0 < padding--)
739 *--bufp = ' ';
741 else
743 bufp += negative_number;
744 while (0 < padding--)
745 *--bufp = '0';
746 if (negative_number)
747 *--bufp = '-';
751 cpy (buf + sizeof (buf) - bufp, bufp);
752 break;
755 case 'H':
756 if (modifier == 'E')
757 goto bad_format;
759 DO_NUMBER (2, tp->tm_hour);
761 case 'I':
762 if (modifier == 'E')
763 goto bad_format;
765 DO_NUMBER (2, hour12);
767 case 'k': /* GNU extension. */
768 if (modifier == 'E')
769 goto bad_format;
771 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
773 case 'l': /* GNU extension. */
774 if (modifier == 'E')
775 goto bad_format;
777 DO_NUMBER_SPACEPAD (2, hour12);
779 case 'j':
780 if (modifier == 'E')
781 goto bad_format;
783 DO_NUMBER (3, 1 + tp->tm_yday);
785 case 'M':
786 if (modifier == 'E')
787 goto bad_format;
789 DO_NUMBER (2, tp->tm_min);
791 case 'm':
792 if (modifier == 'E')
793 goto bad_format;
795 DO_NUMBER (2, tp->tm_mon + 1);
797 case 'n': /* POSIX.2 extension. */
798 add (1, *p = '\n');
799 break;
801 case 'P':
802 to_lowcase = 1;
803 /* FALLTHROUGH */
805 case 'p':
806 cpy (ap_len, ampm);
807 break;
809 case 'R': /* GNU extension. */
810 subfmt = "%H:%M";
811 goto subformat;
813 case 'r': /* POSIX.2 extension. */
814 #ifdef _NL_CURRENT
815 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
816 #endif
817 subfmt = "%I:%M:%S %p";
818 goto subformat;
820 case 'S':
821 if (modifier == 'E')
822 goto bad_format;
824 DO_NUMBER (2, tp->tm_sec);
826 case 's': /* GNU extension. */
828 struct tm ltm;
829 time_t t;
831 ltm = *tp;
832 t = mktime (&ltm);
834 /* Generate string value for T using time_t arithmetic;
835 this works even if sizeof (long) < sizeof (time_t). */
837 bufp = buf + sizeof (buf);
838 negative_number = t < 0;
842 int d = t % 10;
843 t /= 10;
845 if (negative_number)
847 d = -d;
849 /* Adjust if division truncates to minus infinity. */
850 if (0 < -1 % 10 && d < 0)
852 t++;
853 d += 10;
857 *--bufp = d + '0';
859 while (t != 0);
861 digits = 1;
862 goto do_number_sign_and_padding;
865 case 'X':
866 if (modifier == 'O')
867 goto bad_format;
868 #ifdef _NL_CURRENT
869 if (! (modifier == 'E'
870 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
871 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
872 goto subformat;
873 #endif
874 /* Fall through. */
875 case 'T': /* POSIX.2 extension. */
876 subfmt = "%H:%M:%S";
877 goto subformat;
879 case 't': /* POSIX.2 extension. */
880 add (1, *p = '\t');
881 break;
883 case 'u': /* POSIX.2 extension. */
884 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
886 case 'U':
887 if (modifier == 'E')
888 goto bad_format;
890 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
892 case 'V':
893 case 'g': /* GNU extension. */
894 case 'G': /* GNU extension. */
895 if (modifier == 'E')
896 goto bad_format;
898 int year = tp->tm_year + TM_YEAR_BASE;
899 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
901 if (days < 0)
903 /* This ISO week belongs to the previous year. */
904 year--;
905 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
906 tp->tm_wday);
908 else
910 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
911 tp->tm_wday);
912 if (0 <= d)
914 /* This ISO week belongs to the next year. */
915 year++;
916 days = d;
920 switch (*f)
922 case 'g':
923 DO_NUMBER (2, (year % 100 + 100) % 100);
925 case 'G':
926 DO_NUMBER (1, year);
928 default:
929 DO_NUMBER (2, days / 7 + 1);
933 case 'W':
934 if (modifier == 'E')
935 goto bad_format;
937 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
939 case 'w':
940 if (modifier == 'E')
941 goto bad_format;
943 DO_NUMBER (1, tp->tm_wday);
945 case 'Y':
946 #if HAVE_STRUCT_ERA_ENTRY
947 if (modifier == 'E')
949 struct era_entry *era = _nl_get_era_entry (tp);
950 if (era)
952 subfmt = strchr (era->name_fmt, '\0') + 1;
953 goto subformat;
956 #endif
957 if (modifier == 'O')
958 goto bad_format;
959 else
960 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
962 case 'y':
963 #if HAVE_STRUCT_ERA_ENTRY
964 if (modifier == 'E')
966 struct era_entry *era = _nl_get_era_entry (tp);
967 if (era)
969 int delta = tp->tm_year - era->start_date[0];
970 DO_NUMBER (1, (era->offset
971 + (era->direction == '-' ? -delta : delta)));
974 #endif
975 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
977 case 'Z':
978 cpy (zonelen, zone);
979 break;
981 case 'z': /* GNU extension. */
982 if (tp->tm_isdst < 0)
983 break;
986 int diff;
987 #if HAVE_TM_GMTOFF
988 diff = tp->tm_gmtoff;
989 #else
990 struct tm gtm;
991 struct tm ltm;
992 time_t lt;
994 ltm = *tp;
995 lt = mktime (&ltm);
997 if (lt == (time_t) -1)
999 /* mktime returns -1 for errors, but -1 is also a
1000 valid time_t value. Check whether an error really
1001 occurred. */
1002 struct tm tm;
1003 localtime_r (&lt, &tm);
1005 if ((ltm.tm_sec ^ tm.tm_sec)
1006 | (ltm.tm_min ^ tm.tm_min)
1007 | (ltm.tm_hour ^ tm.tm_hour)
1008 | (ltm.tm_mday ^ tm.tm_mday)
1009 | (ltm.tm_mon ^ tm.tm_mon)
1010 | (ltm.tm_year ^ tm.tm_year))
1011 break;
1014 if (! gmtime_r (&lt, &gtm))
1015 break;
1017 diff = tm_diff (&ltm, &gtm);
1018 #endif
1020 if (diff < 0)
1022 add (1, *p = '-');
1023 diff = -diff;
1025 else
1026 add (1, *p = '+');
1028 diff /= 60;
1029 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1032 case '\0': /* GNU extension: % at end of format. */
1033 --f;
1034 /* Fall through. */
1035 default:
1036 /* Unknown format; output the format, including the '%',
1037 since this is most likely the right thing to do if a
1038 multibyte string has been misparsed. */
1039 bad_format:
1041 int flen;
1042 for (flen = 1; f[1 - flen] != '%'; flen++)
1043 continue;
1044 cpy (flen, &f[1 - flen]);
1046 break;
1050 if (p)
1051 *p = '\0';
1052 return i;