[tz] [PROPOSED PATCH 8/9] Add NetBSD-inspired functions for timezone_t objects.
Paul Eggert
eggert at cs.ucla.edu
Tue Aug 26 21:24:03 UTC 2014
Thanks very much for that review.
lennox at cs.columbia.edu wrote:
> These functions aren't documented yet, as far as I can tell?
I had been lazy, and had taken the lead from the STD_INSPIRED functions,
which aren't documented.... But you're right, the new functions should
be, or at least the ones that aren't STD_INSPIRED.
> Since NetBSD doesn't define what a NULL argument to tzalloc does, could I
> suggest that it indeed mean /etc/localtime?
As Alan mentioned NetBSD-current says NULL means UTC, but your idea is
better and Alan likes it too so let's do that.
> I'd also suggest that tzalloc should fail for unknown time zone names,
> rather than silently returning GMT.
Yes, that sounds good too.
Proposed further patches attached for all the above.
-------------- next part --------------
From 636f5e942c8f543e8aea00f83ffbfd1ec2d3fc91 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert at cs.ucla.edu>
Date: Tue, 26 Aug 2014 12:01:30 -0700
Subject: [PROPOSED PATCH 1/4] tzalloc(NULL) now acts like tzset() does when TZ
is unset.
Suggested by Jonathan Lennox in:
http://mm.icann.org/pipermail/tz/2014-August/021529.html
* localtime.c (tzalloc): Treat NULL argument like tzsetwall.
(tzsetwall_unlocked): Remove, replacing with ...
(tzsetlcl): New function, which merges the old tzsetwall and
tzset_unlocked.
(zoneinit): Treat a null NAME like tzsetwall.
(tzsetwall, tzset_unlocked): Rewrite to use tzsetlcl.
* NEWS: Document this.
---
NEWS | 4 ++--
localtime.c | 73 ++++++++++++++++++++++++-------------------------------------
2 files changed, 30 insertions(+), 47 deletions(-)
diff --git a/NEWS b/NEWS
index b8ef455..db9e46f 100644
--- a/NEWS
+++ b/NEWS
@@ -58,8 +58,8 @@ Unreleased, experimental changes
zones simultaneously, e.g., an application where each thread may be
in a different time zone. The new functions are tzalloc, tzfree,
localtime_rz, mktime_z, and (if STD_INSPIRED is also defined)
- posix2time_z and time2posix_z. (Thanks to Alan Barrett for
- helping to debug this.)
+ posix2time_z and time2posix_z. (Thanks to Alan Barrett and
+ Jonathan Lennox for helping to debug this.)
The tz code now attempts to infer TM_GMTOFF and TM_ZONE if not
already defined, to make it easier to configure on common platforms.
diff --git a/localtime.c b/localtime.c
index aee343e..e294a9e 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1174,42 +1174,11 @@ gmtload(struct state *const sp)
tzparse(gmt, sp, true);
}
-static void
-tzsetwall_unlocked(void)
-{
- if (lcl_is_set < 0)
- return;
-#ifdef ALL_STATE
- if (! lclptr)
- lclptr = malloc(sizeof *lclptr);
-#endif
- if (lclptr && ! tzload(NULL, lclptr, true))
- gmtload(lclptr);
- settzname();
- lcl_is_set = -1;
-}
-
-#ifdef STD_INSPIRED
-void
-tzsetwall(void)
-{
- if (lock() != 0)
- return;
- tzsetwall_unlocked();
- unlock();
-}
-#endif
-
static struct state *
zoneinit(struct state *sp, char const *name)
{
if (sp) {
- if (! name
- || (name[0]
- && ! (tzload(name, sp, true)
- || (name[0] != ':' && tzparse(name, sp, false)))))
- gmtload(sp);
- else if (! name[0]) {
+ if (name && ! name[0]) {
/*
** User wants it fast rather than right.
*/
@@ -1220,25 +1189,22 @@ zoneinit(struct state *sp, char const *name)
sp->ttis[0].tt_gmtoff = 0;
sp->ttis[0].tt_abbrind = 0;
strcpy(sp->chars, gmt);
- }
+ } else if (! (tzload(name, sp, true)
+ || (name && name[0] != ':' && tzparse(name, sp, false))))
+ gmtload(sp);
}
return sp;
}
static void
-tzset_unlocked(void)
+tzsetlcl(char const *name)
{
- bool shortname;
- register char const *name = getenv("TZ");
-
- if (!name) {
- tzsetwall_unlocked();
- return;
- }
- shortname = strlen(name) < sizeof lcl_TZname;
- if (0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
+ int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
+ if (lcl < 0
+ ? lcl_is_set < 0
+ : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
return;
- if (shortname)
+ if (0 < lcl)
strcpy(lcl_TZname, name);
#ifdef ALL_STATE
if (! lclptr)
@@ -1246,7 +1212,24 @@ tzset_unlocked(void)
#endif /* defined ALL_STATE */
zoneinit(lclptr, name);
settzname();
- lcl_is_set = shortname;
+ lcl_is_set = lcl;
+}
+
+#ifdef STD_INSPIRED
+void
+tzsetwall(void)
+{
+ if (lock() != 0)
+ return;
+ tzsetlcl(NULL);
+ unlock();
+}
+#endif
+
+static void
+tzset_unlocked(void)
+{
+ return tzsetlcl(getenv("TZ"));
}
void
--
1.9.1
-------------- next part --------------
From 3230f367b09e5b9476253176fa51123e90acb5d2 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert at cs.ucla.edu>
Date: Tue, 26 Aug 2014 12:48:16 -0700
Subject: [PROPOSED PATCH 2/4] * localtime.c (zoneinit, tzalloc): Return NULL
on failure.
Suggested by Jonathan Lennox in:
http://mm.icann.org/pipermail/tz/2014-August/021529.html
---
localtime.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/localtime.c b/localtime.c
index e294a9e..2434167 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1191,7 +1191,7 @@ zoneinit(struct state *sp, char const *name)
strcpy(sp->chars, gmt);
} else if (! (tzload(name, sp, true)
|| (name && name[0] != ':' && tzparse(name, sp, false))))
- gmtload(sp);
+ return NULL;
}
return sp;
}
@@ -1264,7 +1264,10 @@ timezone_t
tzalloc(char const *name)
{
timezone_t sp = malloc(sizeof *sp);
- return zoneinit(sp, name);
+ timezone_t tp = sp ? zoneinit(sp, name) : sp;
+ if (!tp)
+ free(sp);
+ return tp;
}
void
--
1.9.1
-------------- next part --------------
From 9b7dd12d564527191b0d2a7c66bbadace15653e2 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert at cs.ucla.edu>
Date: Tue, 26 Aug 2014 12:49:39 -0700
Subject: [PROPOSED PATCH 3/4] * zdump.c (main): Mention "FOO" if
tzalloc("FOO") fails.
* NEWS: Document this.
---
NEWS | 3 ++-
zdump.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index db9e46f..3ebef9e 100644
--- a/NEWS
+++ b/NEWS
@@ -83,7 +83,8 @@ Unreleased, experimental changes
To build zdump with the system library, use 'make CFLAGS=-DUSE_LTZ=0
TZDOBJS=zdump.o CHECK_TIME_T_ALTERNATIVES='.
- zdump now uses localtime_rz if available, as it's significantly faster.
+ zdump now uses localtime_rz if available, as it's significantly faster,
+ and it can help zdump better diagnose invalid time zone names.
Define HAVE_LOCALTIME_RZ to 0 to suppress this. HAVE_LOCALTIME_TZ
defaults to 1 if NETBSD_INSPIRED && USE_LTZ. When localtime_rz is
not available, zdump now uses localtime_r and tzset if available,
diff --git a/zdump.c b/zdump.c
index 6fdd579..2d82fe5 100644
--- a/zdump.c
+++ b/zdump.c
@@ -634,7 +634,7 @@ main(int argc, char *argv[])
timezone_t tz = tzalloc(argv[i]);
char const *ab;
if (!tz) {
- perror("tzalloc");
+ perror(argv[i]);
return EXIT_FAILURE;
}
if (! (vflag | Vflag)) {
--
1.9.1
-------------- next part --------------
From 2423b5b4a37da406d405649a4f0019c7343f76ca Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert at cs.ucla.edu>
Date: Tue, 26 Aug 2014 14:10:08 -0700
Subject: [PROPOSED PATCH 4/4] Add documentation for the core NetBSD-inspired
functions.
Lack of documentation reported by Jonathan Lennox in:
http://mm.icann.org/pipermail/tz/2014-August/021529.html
* newtzset.3: Document tzalloc and tzfree.
* newctime.3: Document localtime_rz and mktime_z.
* NEWS: Mention this.
---
NEWS | 6 ++++--
newctime.3 | 42 +++++++++++++++++++++++++++++++++--------
newtzset.3 | 64 ++++++++++++++++++++++++++++++++++++++++++++------------------
3 files changed, 84 insertions(+), 28 deletions(-)
diff --git a/NEWS b/NEWS
index 3ebef9e..68d0ae3 100644
--- a/NEWS
+++ b/NEWS
@@ -136,8 +136,10 @@ Unreleased, experimental changes
suggesting a CONTRIBUTING file, and to Tony Finch and Walter Harms
for debugging it.)
- The man pages have been updated to use function prototypes, and
- to document thread-safe variants like localtime_r.
+ The man pages have been updated to use function prototypes,
+ to document thread-safe variants like localtime_r, and to document
+ the NetBSD-inspired functions tzalloc, tzfree, localtime_rz, and
+ mktime_z.
The fields in Link lines have been renamed to be more descriptive
and more like the parameters of 'ln'. LINK-FROM has become TARGET,
diff --git a/newctime.3 b/newctime.3
index accefa5..6667e0d 100644
--- a/newctime.3
+++ b/newctime.3
@@ -25,6 +25,10 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
.B "struct tm *localtime_r(time_t const *restrict clock,"
.B " struct tm *restrict result);"
.PP
+.B "struct tm *localtime_rz(timezone_t restrict zone,"
+.B " time_t const *restrict clock,"
+.B " struct tm *restrict result);"
+.PP
.B struct tm *gmtime(time_t const *clock);
.PP
.B "struct tm *gmtime_r(time_t const *restrict clock,"
@@ -32,6 +36,9 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
.PP
.B time_t mktime(struct tm *tm);
.PP
+.B "time_t mktime_z(timezone_t restrict zone,"
+.B " struct tm *restrict tm);"
+.PP
.B cc ... \*-ltz
.fi
.SH DESCRIPTION
@@ -110,14 +117,6 @@ structure to a string,
as shown in the above example,
and returns a pointer to the string.
.PP
-.IR Ctime_r ,
-.IR localtime_r ,
-.IR gmtime_r ,
-and
-.I asctime_r
-are like their unsuffixed counterparts, except that they accept an
-additional argument specifying where to store the result if successful.
-.PP
.I Mktime
converts the broken-down time,
expressed as local time,
@@ -175,6 +174,33 @@ returns the difference between two calendar times,
.IR time0 ),
expressed in seconds.
.PP
+.IR Ctime_r ,
+.IR localtime_r ,
+.IR gmtime_r ,
+and
+.I asctime_r
+are like their unsuffixed counterparts, except that they accept an
+additional argument specifying where to store the result if successful.
+.PP
+.IR Localtime_rz
+and
+.I mktime_z
+are like their unsuffixed counterparts, except that they accept an
+extra initial
+.B zone
+argument specifying the time zone to be used for conversion.
+If
+.B zone
+is null, UTC is used; otherwise,
+.B zone
+should be have been allocated by
+.I tzalloc
+and should not be freed until after all uses (e.g., by calls to
+.IR strftime )
+of the filled-in
+.B tm_zone
+fields.
+.PP
Declarations of all the functions and externals, and the
.q "tm"
structure,
diff --git a/newtzset.3 b/newtzset.3
index 51c4197..68905a5 100644
--- a/newtzset.3
+++ b/newtzset.3
@@ -7,6 +7,10 @@ tzset \- initialize time conversion information
.el ds - \-
.B #include <time.h>
.PP
+.B timezone_t tzalloc(char const *TZ);
+.PP
+.B void tzfree(timezone_t tz);
+.PP
.B void tzset(void);
.PP
.B cc ... \*-ltz
@@ -21,30 +25,61 @@ tzset \- initialize time conversion information
.de q
\\$3\*(lq\\$1\*(rq\\$2
..
-.I Tzset
-uses the value of the environment variable
+.I Tzalloc
+allocates and returns a time zone object described by
+.BR TZ .
+If
.B TZ
-to set time conversion information used by
-.IR localtime .
+is not a valid time zone description, or if the object cannot be allocated,
+.I tzalloc
+returns a null pointer and sets
+.BR errno .
+.PP
+.I Tzfree
+frees a time zone object
+.BR tz ,
+which should have been successfully allocated by
+.IR tzalloc .
+This invalidates any
+.B tm_zone
+pointers that
+.B tz
+was used to set.
+.PP
+.I Tzset
+acts like
+.BR tzalloc(getenv("TZ")) ,
+except it saves any resulting time zone object into internal
+storage that is accessed by
+.IR localtime ,
+.IR localtime_r ,
+and
+.IR mktime .
+The anonymous shared time zone object is freed by the next call to
+.IR tzset .
+If the implied call to
+.B tzalloc
+fails,
+.I tzset
+falls back on UTC.
+.PP
If
.B TZ
-does not appear in the environment,
-the best available approximation to local wall clock time, as specified
-by the
+is null, the best available approximation to local wall
+clock time, as specified by the
.IR tzfile (5)-format
file
.B localtime
-in the system time conversion information directory, is used by
-.IR localtime .
+in the system time conversion information directory, is used.
If
.B TZ
-appears in the environment but its value is a null string,
+is the empty string,
Universal Time (UT) is used, with the abbreviation "UTC"
and without leap second correction; please see
.IR newctime (3)
for more about UT, UTC, and leap seconds. If
.B TZ
-appears in the environment and its value is not a null string:
+is nonnull and nonempty:
.IP
if the value begins with a colon, it is used as a pathname of a file
from which to read the time conversion information;
@@ -267,13 +302,6 @@ For compatibility with System V Release 3.1, a semicolon
may be used to separate the
.I rule
from the rest of the specification.
-.PP
-If the
-.B TZ
-environment variable does not specify a
-.IR tzfile (5)-format
-and cannot be interpreted as a direct specification,
-UTC is used.
.SH FILES
.ta \w'/usr/local/etc/zoneinfo/posixrules\0\0'u
/usr/local/etc/zoneinfo time zone information directory
--
1.9.1
More information about the tz
mailing list