* time/strftime_l.c (__strftime_internal): Set the default width
padding with zero of "%Ey" to 2.
+ [BZ #24096]
+ * manual/time.texi (strftime): Document "%EC" and "%EY".
+ * time/Makefile (tests): Add tst-strftime2.
+ (LOCALES): Add ja_JP.UTF-8, lo_LA.UTF-8, and th_TH.UTF-8.
+ * time/strftime_l.c (__strftime_internal): Add argument yr_spec to
+ override padding for "%Ey".
+ If an optional flag ('_' or '-') is specified to "%EY", interpret the
+ "%Ey" in the subformat as if decorated with that flag.
+ * time/tst-strftime2.c: New file.
+
2019-01-24 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* support/xsigstack.c (MAP_NORESERVE, MAP_STACK): Define if they
alternative year numbers less than 10). Zero-padding can be
overridden with the '_' or '-' flags (which are GNU extensions).
+* As a GNU extension, the '_' and '-' flags can now be applied to
+ "%EY" to control how the year number is formatted; they have the
+ same effect that they would on "%Ey".
+
Deprecated and removed features, and other changes affecting compatibility:
* The glibc.tune tunable namespace has been renamed to glibc.cpu and the
The century of the year. This is equivalent to the greatest integer not
greater than the year divided by 100.
+If the @code{E} modifier is specified (@code{%EC}), instead produces
+the name of the period for the year (e.g.@: an era name) in the
+locale's alternative calendar.
+
This format was first standardized by POSIX.2-1992 and by @w{ISO C99}.
@item %d
The year as a decimal number, using the Gregorian calendar. Years
before the year @code{1} are numbered @code{0}, @code{-1}, and so on.
+If the @code{E} modifier is specified (@code{%EY}), instead produces a
+complete representation of the year according to the locale's
+alternative calendar. Generally this will be some combination of the
+information produced by @code{%EC} and @code{Ey}. As a GNU extension,
+the formatting flags @code{_} or @code{-} may be used with this
+conversion specifier; they affect how the year number is printed.
+
@item %z
@w{RFC 822}/@w{ISO 8601:1988} style numeric time zone (e.g.,
@code{-0600} or @code{+0100}), or nothing if no time zone is
tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime \
- tst-tzname tst-y2039 bug-mktime4
+ tst-tzname tst-y2039 bug-mktime4 tst-strftime2
include ../Rules
ifeq ($(run-built-tests),yes)
LOCALES := de_DE.ISO-8859-1 en_US.ISO-8859-1 ja_JP.EUC-JP fr_FR.UTF-8 \
- es_ES.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8
+ es_ES.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 \
+ ja_JP.UTF-8 lo_LA.UTF-8 th_TH.UTF-8
include ../gen-locales.mk
$(objpfx)tst-ftime_l.out: $(gen-locales)
#endif
static size_t __strftime_internal (CHAR_T *, size_t, const CHAR_T *,
- const struct tm *, bool *
+ const struct tm *, int, bool *
ut_argument_spec
LOCALE_PARAM) __THROW;
tp = &tmcopy;
#endif
bool tzset_called = false;
- return __strftime_internal (s, maxsize, format, tp, &tzset_called
+ return __strftime_internal (s, maxsize, format, tp, 0, &tzset_called
ut_argument LOCALE_ARG);
}
#ifdef _LIBC
static size_t
__strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format,
- const struct tm *tp, bool *tzset_called
+ const struct tm *tp, int yr_spec, bool *tzset_called
ut_argument_spec LOCALE_PARAM)
{
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
{
CHAR_T *old_start = p;
size_t len = __strftime_internal (NULL, (size_t) -1, subfmt,
- tp, tzset_called ut_argument
- LOCALE_ARG);
+ tp, yr_spec, tzset_called
+ ut_argument LOCALE_ARG);
add (len, __strftime_internal (p, maxsize - i, subfmt,
- tp, tzset_called ut_argument
- LOCALE_ARG));
+ tp, yr_spec, tzset_called
+ ut_argument LOCALE_ARG));
if (to_uppcase)
while (old_start < p)
# else
subfmt = era->era_format;
# endif
+ if (pad != 0)
+ yr_spec = pad;
goto subformat;
}
#else
if (era)
{
int delta = tp->tm_year - era->start_date[0];
+ if (yr_spec != 0)
+ pad = yr_spec;
DO_NUMBER (2, (era->offset
+ delta * era->absolute_direction));
}
--- /dev/null
+/* Verify the behavior of strftime on alternative representation for
+ year.
+
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <locale.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char *locales[] = { "ja_JP.UTF-8", "lo_LA.UTF-8", "th_TH.UTF-8" };
+
+static const char *formats[] = { "%EY", "%_EY", "%-EY" };
+
+static const struct
+{
+ const int d, m, y;
+} dates[] =
+ {
+ { 1, 3, 88 },
+ { 7, 0, 89 },
+ { 8, 0, 89 },
+ { 1, 3, 90 },
+ { 1, 3, 97 },
+ { 1, 3, 98 }
+ };
+
+static char ref[3][3][6][100];
+
+static void
+mkreftable (void)
+{
+ int i, j, k;
+ char era[10];
+ static const int yrj[] = { 63, 64, 1, 2, 9, 10 };
+ static const int yrb[] = { 2531, 2532, 2532, 2533, 2540, 2541 };
+
+ for (i = 0; i < array_length (locales); i++)
+ for (j = 0; j < array_length (formats); j++)
+ for (k = 0; k < array_length (dates); k++)
+ {
+ if (i == 0)
+ {
+ sprintf (era, "%s", (k < 2) ? "\xe6\x98\xad\xe5\x92\x8c"
+ : "\xe5\xb9\xb3\xe6\x88\x90");
+ if (yrj[k] == 1)
+ sprintf (ref[i][j][k], "%s\xe5\x85\x83\xe5\xb9\xb4", era);
+ else
+ {
+ if (j == 0)
+ sprintf (ref[i][j][k], "%s%02d\xe5\xb9\xb4", era, yrj[k]);
+ else if (j == 1)
+ sprintf (ref[i][j][k], "%s%2d\xe5\xb9\xb4", era, yrj[k]);
+ else
+ sprintf (ref[i][j][k], "%s%d\xe5\xb9\xb4", era, yrj[k]);
+ }
+ }
+ else if (i == 1)
+ {
+ sprintf (era, "\xe0\xba\x9e\x2e\xe0\xba\xaa\x2e ");
+ sprintf (ref[i][j][k], "%s%d", era, yrb[k]);
+ }
+ else
+ {
+ sprintf (era, "\xe0\xb8\x9e\x2e\xe0\xb8\xa8\x2e ");
+ sprintf (ref[i][j][k], "%s%d", era, yrb[k]);
+ }
+ }
+}
+
+static int
+do_test (void)
+{
+ int i, j, k, result = 0;
+ struct tm ttm;
+ char date[11], buf[100];
+ size_t r, e;
+
+ mkreftable ();
+ for (i = 0; i < array_length (locales); i++)
+ {
+ if (setlocale (LC_ALL, locales[i]) == NULL)
+ {
+ printf ("locale %s does not exist, skipping...\n", locales[i]);
+ continue;
+ }
+ printf ("[%s]\n", locales[i]);
+ for (j = 0; j < array_length (formats); j++)
+ {
+ for (k = 0; k < array_length (dates); k++)
+ {
+ ttm.tm_mday = dates[k].d;
+ ttm.tm_mon = dates[k].m;
+ ttm.tm_year = dates[k].y;
+ strftime (date, sizeof (date), "%F", &ttm);
+ r = strftime (buf, sizeof (buf), formats[j], &ttm);
+ e = strlen (ref[i][j][k]);
+ printf ("%s\t\"%s\"\t\"%s\"", date, formats[j], buf);
+ if (strcmp (buf, ref[i][j][k]) != 0)
+ {
+ printf ("\tshould be \"%s\"", ref[i][j][k]);
+ if (r != e)
+ printf ("\tgot: %zu, expected: %zu", r, e);
+ result = 1;
+ }
+ else
+ printf ("\tOK");
+ putchar ('\n');
+ }
+ putchar ('\n');
+ }
+ }
+ return result;
+}
+
+#include <support/test-driver.c>