@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -29,13 +30,87 @@ do_test (void)
setenv ("TZ", TZDEFRULES, 1);
tzset ();
const char *stdtz = strdup (tzname[0]);
- setenv ("TZ", "STD-1DST", 1);
- tzset ();
- if (strcmp (tzname[0], "STD") != 0)
+
+ /* Test that proleptic TZ settings set tzname and other external vars.
+ Do not test geographic or empty settings, as POSIX does not require
+ external vars to be set for those cases. */
+ struct tz_test
+ {
+ char const *tz;
+ int daylight;
+ long int timezone;
+ char const *tzname[2];
+ } const tzs_to_test[] =
{
- printf ("FAIL: TZ=STD-1DST, tzname[0] = %s\n", tzname[0]);
- result = 1;
+ { ":STD-1DST", 1, - 1 * 60 * 60, { "STD", "DST" } },
+ { ":AST4ADT", 1, 4 * 60 * 60, { "AST", "ADT" } },
+ { ":QQQ5RRR5", 1, 5 * 60 * 60, { "QQQ", "RRR" } },
+ { ":NZST-12NZDT,M9.5.0,M4.1.0/3", 1, -12 * 60 * 60, { "NZST", "NZDT" } },
+ { ":<-02>2<-01>,M3.5.0/-1,M10.5.0/0", 1, 2 * 60 * 60, { "-02", "-01" } },
+ { ":UTC0", 0, 0, { "UTC", } },
+ };
+ for (int i = 0; i < sizeof tzs_to_test / sizeof *tzs_to_test; i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ char const *tz = tzs_to_test[i].tz + j;
+ if (setenv ("TZ", tz, 1) < 0)
+ {
+ printf ("FAIL: setenv (\"TZ\", \"%s\", 1)\n", tz);
+ result = 1;
+ continue;
+ }
+
+ struct tm *tm;
+ for (int k = 0; k < 5; k++)
+ {
+ time_t t = 0;
+ daylight = INT_MIN;
+ timezone = LONG_MIN;
+ tzname[0] = tzname[1] = (char *) "XYZ";
+
+ char const *method;
+ switch (k)
+ {
+ case 0:
+ case 1: method = "tzset"; tzset (); break;
+ case 2: method = "localtime"; tm = localtime (&t); break;
+ case 3: method = "mktime", mktime (tm); break;
+ case 4: method = "ctime"; ctime (&t); break;
+ }
+
+ if (daylight < 0
+ || (daylight != 0) != tzs_to_test[i].daylight)
+ {
+ printf ("FAIL: TZ=%s, %s, daylight = %d\n",
+ tz, method, daylight);
+ result = 1;
+ }
+ if (timezone != tzs_to_test[i].timezone)
+ {
+ printf ("FAIL: TZ=%s, %s, timezone = %ld\n",
+ tz, method, timezone);
+ result = 1;
+ }
+ if (tzname[0] == NULL
+ || strcmp (tzname[0], tzs_to_test[i].tzname[0]) != 0)
+ {
+ printf ("FAIL: TZ=%s, %s, tzname[0] = %s\n",
+ tz, method, tzname[0] == NULL ? "(NULL)" : tzname[0]);
+ result = 1;
+ }
+ if (tzs_to_test[i].tzname[1] != NULL
+ && (tzname[1] == NULL
+ || strcmp (tzname[1], tzs_to_test[i].tzname[1]) != 0))
+ {
+ printf ("FAIL: TZ=%s, %s, tzname[1] = %s\n",
+ tz, method, tzname[1] == NULL ? "(NULL)" : tzname[0]);
+ result = 1;
+ }
+ }
+ }
}
+
setenv ("TZ", TZDEFRULES, 1);
tzset ();
if (strcmp (tzname[0], stdtz) != 0)
@@ -125,6 +125,7 @@ __tzstring (const char *s)
static char *old_tz;
+/* Update POSIX-required external variables to their saved values. */
static void
update_vars (void)
{
@@ -407,8 +408,11 @@ tzset_internal (int always)
/* Check whether the value changed since the last run. */
if (old_tz != NULL && strcmp (tz, old_tz) == 0)
- /* No change, simply return. */
- return;
+ {
+ /* No change, simply update external vars. */
+ update_vars ();
+ return;
+ }
/* Save the value of `tz'. */
free (old_tz);
@@ -417,7 +421,20 @@ tzset_internal (int always)
/* Try to read a data file. */
__tzfile_read (tz);
if (__use_tzfile)
- return;
+ {
+ /* 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 the rare case of 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];
+ return;
+ }
/* No data file found. Default to UTC without leap seconds if
TZDEFAULT is broken. */
@@ -545,13 +562,6 @@ void
__tzset_unlocked (void)
{
tzset_internal (1);
-
- if (!__use_tzfile)
- {
- /* Set `tzname'. */
- __tzname[0] = (char *) tz_rules[0].name;
- __tzname[1] = (char *) tz_rules[1].name;
- }
}
void