From patchwork Thu Jan 17 06:38:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: TAMUKI Shoichi X-Patchwork-Id: 1026417 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-99363-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linet.gr.jp Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="Ifm51r8y"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43gDtL6xv1z9sD9 for ; Thu, 17 Jan 2019 17:38:34 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:from:date:to:subject:in-reply-to :references:mime-version:content-type; q=dns; s=default; b=AqwyP 1PAoKWpe7xFnY2AZVMt06SdD6jn6enja6e+Wl2ITvnFCssvNyjmfTmU61femWZrr BDCQRwWsj8bUCDkHjY140f07BVg6XOc/KIttDOPmTq40RRvA4ufMDrDKCYYqICi0 PT3RCF4S6ypV3okmj88JuwegvIr3ZDoDzfIlKI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:from:date:to:subject:in-reply-to :references:mime-version:content-type; s=default; bh=57ZW/IESVY4 ekKceelYxSHKsaVI=; b=Ifm51r8yh+vk772BoOT95OZktSR0vID+KrM95e7U8Fq bdUNcoQNEY91DyoRVLFiMn8r8ReqCl3OOwKEn4ry7wEtjS9Fm1reTYBhjoDbtsOC h8k5FXC6eW+DrHyrCWzwJSVgcyAXW1SLT9eB0AKE2g/kRy1EprwMDnG8SSNo6Qco = Received: (qmail 96569 invoked by alias); 17 Jan 2019 06:38:29 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 96554 invoked by uid 89); 17 Jan 2019 06:38:28 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy= X-HELO: mail.linet.jp Message-Id: <201901170638.AA04188@tamuki.linet.gr.jp> From: TAMUKI Shoichi Date: Thu, 17 Jan 2019 15:38:02 +0900 To: libc-alpha@sourceware.org Subject: [PATCH v7 1/2] strftime: Set the default width of "%Ey" to 2 [BZ #23758] In-Reply-To: <201901170635.AA04187@tamuki.linet.gr.jp> References: <201901170635.AA04187@tamuki.linet.gr.jp> MIME-Version: 1.0 In Japanese locales, strftime's alternative year format (%Ey) produces the year of the current era (Japanese calendar). A new era typically begins when a new emperor is enthroned. The year of the current era is therefore usually a one- or two-digit number. Many programs that display Japanese era dates assume that the era year is two digits wide. To improve how these programs display dates during the first nine years of a new era, change %Ey to pad one-digit numbers on the left with a zero. This change applies to all locales. It is expected to be harmless for other locales that use the alternative year format (e.g. lo_LA and th_TH, in which %Ey produces the year of the Buddhist calendar) as those calendars' year numbers are already more than two digits wide, and this is not expected to change. This change needs to be in place before 2019-05-01 CE, as a new era is scheduled to begin on that date. ChangeLog: [BZ #23758] * manual/time.texi (strftime): Document "%Ey". * time/strftime_l.c (__strftime_internal): Set the default width padding with zero of "%Ey" to 2. --- NEWS | 8 ++++++++ manual/time.texi | 7 +++++++ time/strftime_l.c | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index cc20102fda4..5152b5ed0ea 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,14 @@ Major new features: - C-SKY ABIV2 soft-float little-endian - C-SKY ABIV2 hard-float little-endian +* strftime's default formatting of a locale's alternative year (%Ey) + has been changed to zero-pad the year to a minimum of two digits, + like %y. This improves the display of Japanese era years during + the first nine years of a new era, and is expected to be harmless + for all other locales (only Japanese locales regularly have + alternative year numbers less than 10). Zero-padding can be + overridden with the '-' or '_' flags (which are GNU extensions). + Deprecated and removed features, and other changes affecting compatibility: * The glibc.tune tunable namespace has been renamed to glibc.cpu and the diff --git a/manual/time.texi b/manual/time.texi index fd7781c5317..03a8a0e10fc 100644 --- a/manual/time.texi +++ b/manual/time.texi @@ -1568,6 +1568,13 @@ The preferred time of day representation for the current locale. The year without a century as a decimal number (range @code{00} through @code{99}). This is equivalent to the year modulo 100. +If the @code{E} modifier is specified (@code{%Ey}), instead produces +the year number according to a locale-specific alternative calendar. +Unlike @code{%y}, the number is @emph{not} reduced modulo 100. +However, by default it is zero-padded to a minimum of two digits (this +can be overridden by an explicit field width or by the @code{_} and +@code{-} flags). + @item %Y 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. diff --git a/time/strftime_l.c b/time/strftime_l.c index 7ba4179de3e..cbe08e7afb4 100644 --- a/time/strftime_l.c +++ b/time/strftime_l.c @@ -1294,7 +1294,7 @@ __strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format, if (era) { int delta = tp->tm_year - era->start_date[0]; - DO_NUMBER (1, (era->offset + DO_NUMBER (2, (era->offset + delta * era->absolute_direction)); } #else From patchwork Thu Jan 17 06:39:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: TAMUKI Shoichi X-Patchwork-Id: 1026419 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-99364-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linet.gr.jp Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="o78sohdU"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43gDw93F9Zz9sD9 for ; Thu, 17 Jan 2019 17:40:09 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:from:date:to:subject:in-reply-to :references:mime-version:content-type; q=dns; s=default; b=AP/sm KVA4y+2aww8eLwJae2XYaGTiyCBhLph9yokhrU1U3hM7ybF1AVDammYxdG79U6Gn wMATbxbZ5lPaO4Q/PBy+MNEqPvFWFxmLW9H5Qcec+Pvol8ZscpSM8AxK+NFqmJYf aGrxgENVkICY3plBXcBRUJAmquA+33Oi1MkA4k= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:from:date:to:subject:in-reply-to :references:mime-version:content-type; s=default; bh=OJBiC+PbyO3 PKOq6n5uxVzdELF8=; b=o78sohdUpzxUg+RkCTmMKTUnhFu55qowHmNDiju9x0X fitNUZANDRs7EVSeSq8AUABuBQ5cm1nfZS9KXraUKZcFLMKZM9iOZirsDprZ/tx5 ZRy6Ry/HK9nEPIsnRQRX+ubaQ36+EOnYBACBevnnk9EOuXBOmXnB2/BRCzYUuTfQ = Received: (qmail 98630 invoked by alias); 17 Jan 2019 06:40:03 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 98563 invoked by uid 89); 17 Jan 2019 06:40:01 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy=24096, 8601, sprintf X-HELO: mail.linet.jp Message-Id: <201901170639.AA04189@tamuki.linet.gr.jp> From: TAMUKI Shoichi Date: Thu, 17 Jan 2019 15:39:01 +0900 To: libc-alpha@sourceware.org Subject: [PATCH v7 2/2] strftime: Pass the additional flags from "%EY" to "%Ey" [BZ #24096] In-Reply-To: <201901170635.AA04187@tamuki.linet.gr.jp> References: <201901170635.AA04187@tamuki.linet.gr.jp> MIME-Version: 1.0 The full representation of the alternative calendar year (%EY) typically includes an internal use of %Ey. As a GNU extension, apply any flags on %EY (e.g. "%-EY", "%_Ey") to the internal %Ey, allowing users of %EY to control how the year is padded. ChangeLog: [BZ #24096] * manual/time.texi (strftime): Document "%EC" and "%EY". * time/Makefile: Add tst-strftime2 to tests. Also add ja_JP.UTF-8, lo_LA.UTF-8, and th_TH.UTF-8 to LOCALES. * 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. --- NEWS | 4 ++ manual/time.texi | 11 +++++ time/Makefile | 5 +- time/strftime_l.c | 20 +++++--- time/tst-strftime2.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 time/tst-strftime2.c diff --git a/NEWS b/NEWS index 5152b5ed0ea..95e15c86766 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,10 @@ Major new features: 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 diff --git a/manual/time.texi b/manual/time.texi index 03a8a0e10fc..b2867482d31 100644 --- a/manual/time.texi +++ b/manual/time.texi @@ -1393,6 +1393,10 @@ The preferred calendar time representation for the current locale. 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 current 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 @@ -1579,6 +1583,13 @@ can be overridden by an explicit field width or by the @code{_} and 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 diff --git a/time/Makefile b/time/Makefile index d23ba2dee6e..5c6304ece1d 100644 --- a/time/Makefile +++ b/time/Makefile @@ -43,13 +43,14 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ 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) diff --git a/time/strftime_l.c b/time/strftime_l.c index cbe08e7afb4..12d7c0e8744 100644 --- a/time/strftime_l.c +++ b/time/strftime_l.c @@ -434,7 +434,7 @@ static CHAR_T const month_name[][10] = #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; @@ -456,8 +456,9 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format, tmcopy = *tp; tp = &tmcopy; #endif + int yr_spec = 0; /* Override padding for "%Ey". */ bool tzset_called = false; - return __strftime_internal (s, maxsize, format, tp, &tzset_called + return __strftime_internal (s, maxsize, format, tp, &yr_spec, &tzset_called ut_argument LOCALE_ARG); } #ifdef _LIBC @@ -466,7 +467,7 @@ libc_hidden_def (my_strftime) 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 @@ -838,11 +839,12 @@ __strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format, { 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)); + *yr_spec = 0; if (to_uppcase) while (old_start < p) @@ -1273,6 +1275,8 @@ __strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format, # else subfmt = era->era_format; # endif + if (pad != 0) + *yr_spec = pad; goto subformat; } #else @@ -1294,6 +1298,8 @@ __strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format, 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)); } diff --git a/time/tst-strftime2.c b/time/tst-strftime2.c new file mode 100644 index 00000000000..57d2144c83c --- /dev/null +++ b/time/tst-strftime2.c @@ -0,0 +1,132 @@ +/* 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 + . */ + +#include +#include +#include +#include +#include + +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