From patchwork Sun Jan 5 05:57:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Eggert X-Patchwork-Id: 104095 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 33C893858C66 for ; Sun, 5 Jan 2025 06:52:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 33C893858C66 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=cs.ucla.edu header.i=@cs.ucla.edu header.a=rsa-sha256 header.s=9D0B346E-2AEB-11ED-9476-E14B719DCE6C header.b=OY3JPr0B X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail.cs.ucla.edu (mail.cs.ucla.edu [131.179.128.66]) by sourceware.org (Postfix) with ESMTPS id 6F13B385840E for ; Sun, 5 Jan 2025 06:00:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6F13B385840E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=cs.ucla.edu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=cs.ucla.edu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6F13B385840E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=131.179.128.66 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736056816; cv=none; b=To6uCafs4YyavD2vg0xHkG9VZnE6iixF4QwGFvfCmRNVJTyzO8yHf3hU3ues3uJRC3SuPEYET0XsV9nrt/HMwsh1RDgmS5A4IF4MQk/Du+0/Rah6obLLkuj14jhHnfU7dtfazlH7lBSSyK9tNYB2VxMwgtiCmFbPw6AtPGu5tt4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736056816; c=relaxed/simple; bh=+HJejJq8mlrJZL8xb4OoD6GP7O9C5UqoYF3GukVrL+M=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=jCtfO8d5oQkAaa2q1hIAiOzS+1JasyFtEgUsGL3F1vK9Asd0u6i+InqvOevfAstrnKolWEbKGzwvmuA4qtZ+lVYFYJvXN2z7zlzTsaZ9bEXwXOW+bRQmYwDvrTsUAG9VuYXrfl5tb7vnquewQgTKl1SuWS0pGJE2vdkxtre5QiM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6F13B385840E Received: from localhost (localhost [127.0.0.1]) by mail.cs.ucla.edu (Postfix) with ESMTP id 1C5D93C123845 for ; Sat, 4 Jan 2025 22:00:15 -0800 (PST) Received: from mail.cs.ucla.edu ([127.0.0.1]) by localhost (mail.cs.ucla.edu [127.0.0.1]) (amavis, port 10032) with ESMTP id PTuIguwB0tgi; Sat, 4 Jan 2025 22:00:14 -0800 (PST) Received: from localhost (localhost [127.0.0.1]) by mail.cs.ucla.edu (Postfix) with ESMTP id 972653C123844; Sat, 4 Jan 2025 22:00:14 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.10.3 mail.cs.ucla.edu 972653C123844 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cs.ucla.edu; s=9D0B346E-2AEB-11ED-9476-E14B719DCE6C; t=1736056814; bh=X28icvuKlE8Tz0ZRD05/iOd3ZB/yQzzLPRPh6W7f60A=; h=From:To:Date:Message-ID:MIME-Version; b=OY3JPr0B2EJM6tfb15hocvGiXGn0zKxCi5dGgrIk3gLejmfEMqjJjq9lvpvgYqOVu s1q+fOm4w17+T8as2lvXToLWvE4CXqcgL8ASe2kje5ePO6kw+a+3Poc8l0GA12oEJm JyJyw0x9t9M9PMaj2HqevDkeDyR5p/DX97B6xePt4OvBipLNLycQGafy441FBwPMMs uVWx8J93IMkx2IOYh6eVlnpmF2iYUVkjvcYdWhQ/OJv75A0UF4FtXIfuyjePd+3PLU XP7jvfBC56jg3UqZoG1bnrcsHr+Gru5plTfunCDaSthbvmganpI+99MW5rHVeirHAZ 1SeW62kRlUL/A== X-Virus-Scanned: amavis at mail.cs.ucla.edu Received: from mail.cs.ucla.edu ([127.0.0.1]) by localhost (mail.cs.ucla.edu [127.0.0.1]) (amavis, port 10026) with ESMTP id ewGVv2lg6eIX; Sat, 4 Jan 2025 22:00:14 -0800 (PST) Received: from wing.home (unknown [47.154.28.214]) by mail.cs.ucla.edu (Postfix) with ESMTPSA id 801023C082EB9; Sat, 4 Jan 2025 22:00:14 -0800 (PST) From: Paul Eggert To: libc-alpha@sourceware.org Cc: Paul Eggert Subject: [PATCH 46/59] tzset, not localtime, now parses TZif TZ spec Date: Sat, 4 Jan 2025 21:57:21 -0800 Message-ID: <20250105055750.1668721-47-eggert@cs.ucla.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <01207110-bd60-46ae-9c08-fb39c2011067@cs.ucla.edu> References: <01207110-bd60-46ae-9c08-fb39c2011067@cs.ucla.edu> MIME-Version: 1.0 X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org It's typically faster to parse a TZif file's TZ spec once after TZ changes instead of parsing it on every call to localtime, as most slim TZif files' last transitions precede the current time. * time/tzfile.c (rule_stdoff, daylight_saved): Remove static vars. All uses removed. (__tzfile_read): Parse the tzspec here. Simplify the guesswork for tzname etc.: if a tzspec exists, use its proleptic values as this is more likely to be what obsolescent code wants; otherwise, simplify three loops into one. (__tzfile_compute): Do not parse tzspec, as tzset now does that. * time/tzset.c (tzset_internal): When TZ hasn't changed, update external vars only if TZ is proleptic. (tzset_internal): Do not attempt to migrate __tzfile_read's settings of tzname etc. into tz_rules as that would mess up later use by __tzfile_compute of a parsed tzspec. --- time/tzfile.c | 99 ++++++++++++++++++++------------------------------- time/tzset.c | 27 +++++--------- 2 files changed, 47 insertions(+), 79 deletions(-) diff --git a/time/tzfile.c b/time/tzfile.c index dd5973b76d..f86df0c8d5 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -64,15 +64,10 @@ static unsigned char *type_idxs; static tzidx typecnt; static struct ttinfo *types; static char *zone_names; -static long int rule_stdoff; static tzidx leapcnt; static struct leap *leaps; static char *tzspec; -/* Used to restore the daylight variable during time conversion, as if - tzset had been called. */ -static int daylight_saved; - #include #include @@ -516,65 +511,53 @@ __tzfile_read (const char *file) if (__tzstring (&zone_names[types[i].idx]) == NULL) goto ret_free_transitions; - /* Find the standard and daylight time offsets used by the rule file. - We choose the offsets in the types of each flavor that are - transitioned to earliest in time. */ - __tzname[0] = NULL; - __tzname[1] = NULL; - for (i = timecnt; i > 0; i--) - { - struct ttinfo *ttype = &types[type_idxs[i - 1]]; - unsigned char dst = ttype->dst; - - if (__tzname[dst] == NULL) - { - __tzname[dst] = __tzstring (&zone_names[ttype->idx]); + /* POSIX does not say what daylight, timezone and tzname should be; + try to set them to something reasonable. */ - if (__tzname[1 - dst] != NULL) - break; - } - } - if (__tzname[0] == NULL) + if (tzspec != NULL) { - /* This should only happen if there are no transition rules. - In this case there's usually only one single type, unless - e.g. the data file has a truncated time-range. */ - __tzname[0] = __tzstring (zone_names); + /* The usual case with tzspec; just use its values. */ + if (__glibc_unlikely (! __tzset_parse_tz (tzspec))) + goto ret_free_transitions; } - if (__tzname[1] == NULL) - __tzname[1] = __tzname[0]; - - daylight_saved = 0; - if (timecnt == 0) - /* Use the first rule (which should also be the only one). */ - rule_stdoff = types[0].utoff; else { - rule_stdoff = 0; - - /* Search for the last rule with a standard time offset. This - will be used for the global timezone variable. */ - i = timecnt - 1; - do - if (!types[type_idxs[i]].dst) - { - rule_stdoff = types[type_idxs[i]].utoff; + /* The unusual case without tzspec; infer from transitions. + Default to the first type's offset and isdst. */ + __timezone = -types[0].utoff; + __daylight = types[0].dst; + + /* Find the abbr and offset for the last transition to standard time, + and the abbr for the last transition to DST. */ + __tzname[0] = NULL; + __tzname[1] = NULL; + for (i = timecnt; i > 0; i--) + { + struct ttinfo *ttype = &types[type_idxs[i - 1]]; + unsigned char dst = ttype->dst; + + if (__tzname[dst] == NULL) + { + __tzname[dst] = __tzstring (&zone_names[ttype->idx]); + if (!dst) + __timezone = -ttype->utoff; + } + + if (__tzname[1 - dst] != NULL) break; - } - else - daylight_saved = 1; - while (i-- > 0); - - /* Keep searching to see if there is a DST rule. This - information will be used to set the global daylight - variable. */ - while (i-- > 0 && !daylight_saved) - daylight_saved = types[type_idxs[i]].dst; + } + /* With no appropriate transitions, default standard time's + abbreviation to that of the first type, and default DST's + abbreviation to that of standard time. Also, set 'daylight' + if a DST transition was found. */ + if (__tzname[0] == NULL) + __tzname[0] = __tzstring (&zone_names[types[0].idx]); + if (__tzname[1] == NULL) + __tzname[1] = __tzname[0]; + else + __daylight = 1; } - __daylight = daylight_saved; - __timezone = -rule_stdoff; - /* Remember the inode and device number and modification time. */ tzfile_dev = st.st_dev; tzfile_ino = st.st_ino; @@ -618,10 +601,6 @@ __tzfile_compute (__time64_t timer, int use_localtime, goto found; } - /* Parse the proleptic TZ string. If this fails do not use it. */ - if (__glibc_unlikely (! __tzset_parse_tz (tzspec))) - goto use_last; - /* Convert to broken down structure. If this fails do not use the string. */ if (__glibc_unlikely (__offtime (timer, 0, 0, tp) == NULL)) diff --git a/time/tzset.c b/time/tzset.c index add0073e0d..b5bbd05573 100644 --- a/time/tzset.c +++ b/time/tzset.c @@ -412,15 +412,18 @@ tzset_internal (bool always) tz = TZDEFAULT; /* A leading colon means "implementation defined syntax". - We ignore the colon and always use the same algorithm: + Ignore the colon and always use the same algorithm: try a data file, and if none exists parse the 1003.1 syntax. */ if (*tz == ':') ++tz; - /* If the value changed has not since the last run, - simply update internal vars. */ + /* If the value has not changed since the last run, + simply update external vars if POSIX requires it. */ if (old_tz != NULL && strcmp (tz, old_tz) == 0) - update_vars (); + { + if (!use_tzfile) + update_vars (); + } else { /* Save the value of 'tz'. */ @@ -429,21 +432,7 @@ tzset_internal (bool always) /* Try to read a data file. */ use_tzfile = __tzfile_read (tz); - if (use_tzfile) - { - /* Save equivalent of 'daylight' for later use by update_vars. - Although the other external variables have unspecified values - and so need not be saved in the usual case, save them anyway, - as POSIX requires this for rare file-backed proleptic - TZ strings like "EST5EDT", and it is more likely to match user - expectations for geographical TZ strings. */ - enum tz_rule_type some_DST = J0; /* anything but NO_DST */ - tz_rules[1].type = NO_DST + __daylight * (some_DST - NO_DST); - tz_rules[0].offset = -__timezone; - tz_rules[0].name = __tzname[0]; - tz_rules[1].name = __tzname[1]; - } - else + if (!use_tzfile) { /* No data file found. Default to UTC without leap seconds if TZDEFAULT is broken. */