Update.
[glibc.git] / time / strftime.c
blob4cb6c9e26063d5ed9de81fc72c2edfea8aa683d4
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;
285 #if ! HAVE_TM_GMTOFF
286 /* Yield the difference between *A and *B,
287 measured in seconds, ignoring leap seconds. */
288 static int tm_diff __P ((const struct tm *, const struct tm *));
289 static int
290 tm_diff (a, b)
291 const struct tm *a;
292 const struct tm *b;
294 /* Compute intervening leap days correctly even if year is negative.
295 Take care to avoid int overflow in leap day calculations,
296 but it's OK to assume that A and B are close to each other. */
297 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
298 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
299 int a100 = a4 / 25 - (a4 % 25 < 0);
300 int b100 = b4 / 25 - (b4 % 25 < 0);
301 int a400 = a100 >> 2;
302 int b400 = b100 >> 2;
303 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
304 int years = a->tm_year - b->tm_year;
305 int days = (365 * years + intervening_leap_days
306 + (a->tm_yday - b->tm_yday));
307 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
308 + (a->tm_min - b->tm_min))
309 + (a->tm_sec - b->tm_sec));
311 #endif /* ! HAVE_TM_GMTOFF */
315 /* The number of days from the first day of the first ISO week of this
316 year to the year day YDAY with week day WDAY. ISO weeks start on
317 Monday; the first ISO week has the year's first Thursday. YDAY may
318 be as small as YDAY_MINIMUM. */
319 #define ISO_WEEK_START_WDAY 1 /* Monday */
320 #define ISO_WEEK1_WDAY 4 /* Thursday */
321 #define YDAY_MINIMUM (-366)
322 static int iso_week_days __P ((int, int));
323 #ifdef __GNUC__
324 inline
325 #endif
326 static int
327 iso_week_days (yday, wday)
328 int yday;
329 int wday;
331 /* Add enough to the first operand of % to make it nonnegative. */
332 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
333 return (yday
334 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
335 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
339 #ifndef _NL_CURRENT
340 static char const weekday_name[][10] =
342 "Sunday", "Monday", "Tuesday", "Wednesday",
343 "Thursday", "Friday", "Saturday"
345 static char const month_name[][10] =
347 "January", "February", "March", "April", "May", "June",
348 "July", "August", "September", "October", "November", "December"
350 #endif
353 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
354 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
355 Work around this bug by copying *tp before it might be munged. */
356 size_t _strftime_copytm __P ((char *, size_t, const char *,
357 const struct tm *));
358 size_t
359 strftime (s, maxsize, format, tp)
360 char *s;
361 size_t maxsize;
362 const char *format;
363 const struct tm *tp;
365 struct tm tmcopy;
366 tmcopy = *tp;
367 return _strftime_copytm (s, maxsize, format, &tmcopy);
369 # ifdef strftime
370 # undef strftime
371 # endif
372 # define strftime(S, Maxsize, Format, Tp) \
373 _strftime_copytm (S, Maxsize, Format, Tp)
374 #endif
377 /* Write information from TP into S according to the format
378 string FORMAT, writing no more that MAXSIZE characters
379 (including the terminating '\0') and returning number of
380 characters written. If S is NULL, nothing will be written
381 anywhere, so to determine how many characters would be
382 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
383 size_t
384 strftime (s, maxsize, format, tp)
385 char *s;
386 size_t maxsize;
387 const char *format;
388 const struct tm *tp;
390 int hour12 = tp->tm_hour;
391 #ifdef _NL_CURRENT
392 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
393 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
394 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
395 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
396 const char *const ampm = _NL_CURRENT (LC_TIME,
397 hour12 > 11 ? PM_STR : AM_STR);
398 size_t aw_len = strlen (a_wkday);
399 size_t am_len = strlen (a_month);
400 size_t ap_len = strlen (ampm);
401 #else
402 const char *const f_wkday = weekday_name[tp->tm_wday];
403 const char *const f_month = month_name[tp->tm_mon];
404 const char *const a_wkday = f_wkday;
405 const char *const a_month = f_month;
406 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
407 size_t aw_len = 3;
408 size_t am_len = 3;
409 size_t ap_len = 2;
410 #endif
411 size_t wkday_len = strlen (f_wkday);
412 size_t month_len = strlen (f_month);
413 const char *zone;
414 size_t zonelen;
415 size_t i = 0;
416 char *p = s;
417 const char *f;
419 zone = NULL;
420 #if !defined _LIBC && HAVE_TM_ZONE
421 /* XXX We have some problems here. First, the string pointed to by
422 tm_zone is dynamically allocated while loading the zone data. But
423 when another zone is loaded since the information in TP were
424 computed this would be a stale pointer.
425 The second problem is the POSIX test suite which assumes setting
426 the environment variable TZ to a new value before calling strftime()
427 will influence the result (the %Z format) even if the information in
428 TP is computed with a totally different time zone. --drepper@gnu */
429 zone = (const char *) tp->tm_zone;
430 #endif
431 #if HAVE_TZNAME
432 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
433 time zone names contained in the external variable `tzname' shall
434 be set as if the tzset() function had been called. */
435 # if HAVE_TZSET
436 tzset ();
437 # endif
439 if (!(zone && *zone) && tp->tm_isdst >= 0)
440 zone = tzname[tp->tm_isdst];
441 #endif
442 if (! zone)
443 zone = ""; /* POSIX.2 requires the empty string here. */
445 zonelen = strlen (zone);
447 if (hour12 > 12)
448 hour12 -= 12;
449 else
450 if (hour12 == 0) hour12 = 12;
452 for (f = format; *f != '\0'; ++f)
454 int pad; /* Padding for number ('-', '_', or 0). */
455 int modifier; /* Field modifier ('E', 'O', or 0). */
456 int digits; /* Max digits for numeric format. */
457 int number_value; /* Numeric value to be printed. */
458 int negative_number; /* 1 if the number is negative. */
459 const char *subfmt;
460 char *bufp;
461 char buf[1 + (sizeof (int) < sizeof (time_t)
462 ? INT_STRLEN_BOUND (time_t)
463 : INT_STRLEN_BOUND (int))];
464 int width = -1;
465 int to_lowcase = 0;
466 int to_uppcase = 0;
468 #if DO_MULTIBYTE
470 switch (*f)
472 case '%':
473 break;
475 case '\a': case '\b': case '\t': case '\n':
476 case '\v': case '\f': case '\r':
477 case ' ': case '!': case '"': case '#': case '&': case'\'':
478 case '(': case ')': case '*': case '+': case ',': case '-':
479 case '.': case '/': case '0': case '1': case '2': case '3':
480 case '4': case '5': case '6': case '7': case '8': case '9':
481 case ':': case ';': case '<': case '=': case '>': case '?':
482 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
483 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
484 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
485 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
486 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
487 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
488 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
489 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
490 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
491 case 'x': case 'y': case 'z': case '{': case '|': case '}':
492 case '~':
493 /* The C Standard requires these 98 characters (plus '%') to
494 be in the basic execution character set. None of these
495 characters can start a multibyte sequence, so they need
496 not be analyzed further. */
497 add (1, *p = *f);
498 continue;
500 default:
501 /* Copy this multibyte sequence until we reach its end, find
502 an error, or come back to the initial shift state. */
504 mbstate_t mbstate = mbstate_zero;
505 size_t len = 0;
509 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
511 if (bytes == 0)
512 break;
514 if (bytes == (size_t) -2 || bytes == (size_t) -1)
516 len++;
517 break;
520 len += bytes;
522 while (! mbsinit (&mbstate));
524 cpy (len, f);
525 continue;
529 #else /* ! DO_MULTIBYTE */
531 /* Either multibyte encodings are not supported, or they are
532 safe for formats, so any non-'%' byte can be copied through. */
533 if (*f != '%')
535 add (1, *p = *f);
536 continue;
539 #endif /* ! DO_MULTIBYTE */
541 /* Check for flags that can modify a format. */
542 pad = 0;
543 while (1)
545 switch (*++f)
547 /* This influences the number formats. */
548 case '_':
549 case '-':
550 case '0':
551 pad = *f;
552 continue;
554 /* This changes textual output. */
555 case '^':
556 to_uppcase = 1;
557 continue;
559 default:
560 break;
562 break;
565 /* As a GNU extension we allow to specify the field width. */
566 if (ISDIGIT (*f))
568 width = 0;
571 width *= 10;
572 width += *f - '0';
573 ++f;
575 while (ISDIGIT (*f));
578 /* Check for modifiers. */
579 switch (*f)
581 case 'E':
582 case 'O':
583 modifier = *f++;
584 break;
586 default:
587 modifier = 0;
588 break;
591 /* Now do the specified format. */
592 switch (*f)
594 #define DO_NUMBER(d, v) \
595 digits = d; number_value = v; goto do_number
596 #define DO_NUMBER_SPACEPAD(d, v) \
597 digits = d; number_value = v; goto do_number_spacepad
599 case '%':
600 if (modifier != 0)
601 goto bad_format;
602 add (1, *p = *f);
603 break;
605 case 'a':
606 if (modifier != 0)
607 goto bad_format;
608 cpy (aw_len, a_wkday);
609 break;
611 case 'A':
612 if (modifier != 0)
613 goto bad_format;
614 cpy (wkday_len, f_wkday);
615 break;
617 case 'b':
618 case 'h': /* POSIX.2 extension. */
619 if (modifier != 0)
620 goto bad_format;
621 cpy (am_len, a_month);
622 break;
624 case 'B':
625 if (modifier != 0)
626 goto bad_format;
627 cpy (month_len, f_month);
628 break;
630 case 'c':
631 if (modifier == 'O')
632 goto bad_format;
633 #ifdef _NL_CURRENT
634 if (! (modifier == 'E'
635 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
636 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
637 #else
638 subfmt = "%a %b %e %H:%M:%S %Y";
639 #endif
641 subformat:
643 char *old_start = p;
644 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
645 if (len == 0 && *subfmt)
646 return 0;
647 add (len, strftime (p, maxsize - i, subfmt, tp));
649 if (to_uppcase)
650 while (old_start < p)
652 *old_start = TOUPPER (*old_start);
653 ++old_start;
656 break;
658 case 'C': /* POSIX.2 extension. */
659 if (modifier == 'O')
660 goto bad_format;
661 #if HAVE_STRUCT_ERA_ENTRY
662 if (modifier == 'E')
664 struct era_entry *era = _nl_get_era_entry (tp);
665 if (era)
667 size_t len = strlen (era->name_fmt);
668 cpy (len, era->name_fmt);
669 break;
672 #endif
674 int year = tp->tm_year + TM_YEAR_BASE;
675 DO_NUMBER (1, year / 100 - (year % 100 < 0));
678 case 'x':
679 if (modifier == 'O')
680 goto bad_format;
681 #ifdef _NL_CURRENT
682 if (! (modifier == 'E'
683 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
684 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
685 goto subformat;
686 #endif
687 /* Fall through. */
688 case 'D': /* POSIX.2 extension. */
689 if (modifier != 0)
690 goto bad_format;
691 subfmt = "%m/%d/%y";
692 goto subformat;
694 case 'd':
695 if (modifier == 'E')
696 goto bad_format;
698 DO_NUMBER (2, tp->tm_mday);
700 case 'e': /* POSIX.2 extension. */
701 if (modifier == 'E')
702 goto bad_format;
704 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
706 /* All numeric formats set DIGITS and NUMBER_VALUE and then
707 jump to one of these two labels. */
709 do_number_spacepad:
710 /* Force `_' flag unless overwritten by `0' flag. */
711 if (pad != '0')
712 pad = '_';
714 do_number:
715 /* Format the number according to the MODIFIER flag. */
717 #ifdef _NL_CURRENT
718 if (modifier == 'O' && 0 <= number_value)
720 /* Get the locale specific alternate representation of
721 the number NUMBER_VALUE. If none exist NULL is returned. */
722 const char *cp = _nl_get_alt_digit (number_value);
724 if (cp != NULL)
726 size_t digitlen = strlen (cp);
727 if (digitlen != 0)
729 cpy (digitlen, cp);
730 break;
734 #endif
736 unsigned int u = number_value;
738 bufp = buf + sizeof (buf);
739 negative_number = number_value < 0;
741 if (negative_number)
742 u = -u;
745 *--bufp = u % 10 + '0';
746 while ((u /= 10) != 0);
749 do_number_sign_and_padding:
750 if (negative_number)
751 *--bufp = '-';
753 if (pad != '-')
755 int padding = digits - (buf + sizeof (buf) - bufp);
757 if (pad == '_')
759 while (0 < padding--)
760 *--bufp = ' ';
762 else
764 bufp += negative_number;
765 while (0 < padding--)
766 *--bufp = '0';
767 if (negative_number)
768 *--bufp = '-';
772 cpy (buf + sizeof (buf) - bufp, bufp);
773 break;
776 case 'H':
777 if (modifier == 'E')
778 goto bad_format;
780 DO_NUMBER (2, tp->tm_hour);
782 case 'I':
783 if (modifier == 'E')
784 goto bad_format;
786 DO_NUMBER (2, hour12);
788 case 'k': /* GNU extension. */
789 if (modifier == 'E')
790 goto bad_format;
792 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
794 case 'l': /* GNU extension. */
795 if (modifier == 'E')
796 goto bad_format;
798 DO_NUMBER_SPACEPAD (2, hour12);
800 case 'j':
801 if (modifier == 'E')
802 goto bad_format;
804 DO_NUMBER (3, 1 + tp->tm_yday);
806 case 'M':
807 if (modifier == 'E')
808 goto bad_format;
810 DO_NUMBER (2, tp->tm_min);
812 case 'm':
813 if (modifier == 'E')
814 goto bad_format;
816 DO_NUMBER (2, tp->tm_mon + 1);
818 case 'n': /* POSIX.2 extension. */
819 add (1, *p = '\n');
820 break;
822 case 'P':
823 to_lowcase = 1;
824 /* FALLTHROUGH */
826 case 'p':
827 cpy (ap_len, ampm);
828 break;
830 case 'R': /* GNU extension. */
831 subfmt = "%H:%M";
832 goto subformat;
834 case 'r': /* POSIX.2 extension. */
835 #ifdef _NL_CURRENT
836 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
837 #endif
838 subfmt = "%I:%M:%S %p";
839 goto subformat;
841 case 'S':
842 if (modifier == 'E')
843 goto bad_format;
845 DO_NUMBER (2, tp->tm_sec);
847 case 's': /* GNU extension. */
849 struct tm ltm;
850 time_t t;
852 ltm = *tp;
853 t = mktime (&ltm);
855 /* Generate string value for T using time_t arithmetic;
856 this works even if sizeof (long) < sizeof (time_t). */
858 bufp = buf + sizeof (buf);
859 negative_number = t < 0;
863 int d = t % 10;
864 t /= 10;
866 if (negative_number)
868 d = -d;
870 /* Adjust if division truncates to minus infinity. */
871 if (0 < -1 % 10 && d < 0)
873 t++;
874 d += 10;
878 *--bufp = d + '0';
880 while (t != 0);
882 digits = 1;
883 goto do_number_sign_and_padding;
886 case 'X':
887 if (modifier == 'O')
888 goto bad_format;
889 #ifdef _NL_CURRENT
890 if (! (modifier == 'E'
891 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
892 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
893 goto subformat;
894 #endif
895 /* Fall through. */
896 case 'T': /* POSIX.2 extension. */
897 subfmt = "%H:%M:%S";
898 goto subformat;
900 case 't': /* POSIX.2 extension. */
901 add (1, *p = '\t');
902 break;
904 case 'u': /* POSIX.2 extension. */
905 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
907 case 'U':
908 if (modifier == 'E')
909 goto bad_format;
911 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
913 case 'V':
914 case 'g': /* GNU extension. */
915 case 'G': /* GNU extension. */
916 if (modifier == 'E')
917 goto bad_format;
919 int year = tp->tm_year + TM_YEAR_BASE;
920 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
922 if (days < 0)
924 /* This ISO week belongs to the previous year. */
925 year--;
926 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
927 tp->tm_wday);
929 else
931 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
932 tp->tm_wday);
933 if (0 <= d)
935 /* This ISO week belongs to the next year. */
936 year++;
937 days = d;
941 switch (*f)
943 case 'g':
944 DO_NUMBER (2, (year % 100 + 100) % 100);
946 case 'G':
947 DO_NUMBER (1, year);
949 default:
950 DO_NUMBER (2, days / 7 + 1);
954 case 'W':
955 if (modifier == 'E')
956 goto bad_format;
958 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
960 case 'w':
961 if (modifier == 'E')
962 goto bad_format;
964 DO_NUMBER (1, tp->tm_wday);
966 case 'Y':
967 #if HAVE_STRUCT_ERA_ENTRY
968 if (modifier == 'E')
970 struct era_entry *era = _nl_get_era_entry (tp);
971 if (era)
973 subfmt = strchr (era->name_fmt, '\0') + 1;
974 goto subformat;
977 #endif
978 if (modifier == 'O')
979 goto bad_format;
980 else
981 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
983 case 'y':
984 #if HAVE_STRUCT_ERA_ENTRY
985 if (modifier == 'E')
987 struct era_entry *era = _nl_get_era_entry (tp);
988 if (era)
990 int delta = tp->tm_year - era->start_date[0];
991 DO_NUMBER (1, (era->offset
992 + (era->direction == '-' ? -delta : delta)));
995 #endif
996 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
998 case 'Z':
999 cpy (zonelen, zone);
1000 break;
1002 case 'z': /* GNU extension. */
1003 if (tp->tm_isdst < 0)
1004 break;
1007 int diff;
1008 #if HAVE_TM_GMTOFF
1009 diff = tp->tm_gmtoff;
1010 #else
1011 struct tm gtm;
1012 struct tm ltm;
1013 time_t lt;
1015 ltm = *tp;
1016 lt = mktime (&ltm);
1018 if (lt == (time_t) -1)
1020 /* mktime returns -1 for errors, but -1 is also a
1021 valid time_t value. Check whether an error really
1022 occurred. */
1023 struct tm tm;
1024 localtime_r (&lt, &tm);
1026 if ((ltm.tm_sec ^ tm.tm_sec)
1027 | (ltm.tm_min ^ tm.tm_min)
1028 | (ltm.tm_hour ^ tm.tm_hour)
1029 | (ltm.tm_mday ^ tm.tm_mday)
1030 | (ltm.tm_mon ^ tm.tm_mon)
1031 | (ltm.tm_year ^ tm.tm_year))
1032 break;
1035 if (! gmtime_r (&lt, &gtm))
1036 break;
1038 diff = tm_diff (&ltm, &gtm);
1039 #endif
1041 if (diff < 0)
1043 add (1, *p = '-');
1044 diff = -diff;
1046 else
1047 add (1, *p = '+');
1049 diff /= 60;
1050 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1053 case '\0': /* GNU extension: % at end of format. */
1054 --f;
1055 /* Fall through. */
1056 default:
1057 /* Unknown format; output the format, including the '%',
1058 since this is most likely the right thing to do if a
1059 multibyte string has been misparsed. */
1060 bad_format:
1062 int flen;
1063 for (flen = 1; f[1 - flen] != '%'; flen++)
1064 continue;
1065 cpy (flen, &f[1 - flen]);
1067 break;
1071 if (p)
1072 *p = '\0';
1073 return i;