[tz] default value of TZDEFAULT

Steve Summit scs at eskimo.com
Mon Dec 11 12:33:20 UTC 2017


[This is a tzcode issue, not tzdata.  Your regular discussion of
zone definition and naming issues will resume shortly. :-) ]

Consider this simple little program:

	#include <stdio.h>
	#include <time.h>

	int main()
	{
		time_t t = time(NULL);
		struct tm *tmp = localtime(&t);
		puts(asctime(tmp));
		return 0;
	}

There's nothing special about this program (that's the point).
But suppose I download tzcode or tzdb and then compile the
little program (call it lt.c) along with a just-built
localtime(), like this:

	make localtime.o
	cc -o lt lt.c localtime.o

But if I then run 'lt', it is likely not to work -- there's a
pretty good chance it will print the current time in UTC, not
my local time zone.  If it fails, one reason is that it didn't
successfully find my system's already-installed tz files.
(That is, I made no attempt to build or install any new tz files.)

The reason it didn't find them is obvious enough, and the
Makefile contains all the hints I need:

	TOPDIR=		/usr/local
	# "Compiled" time zone information is placed in the "TZDIR" directory
	# (and subdirectories).
	# Use an absolute path name for TZDIR unless you're just testing the software.
	# TZDIR_BASENAME should not contain "/" and should not be ".", ".." or empty.
	TZDIR_BASENAME=	zoneinfo
	TZDIR=		$(TOPDIR)/etc/$(TZDIR_BASENAME)

And, sure enough, on my system, the already-installed tz files
are not in /usr/local, they're in /usr/share.  So it looks like
if I change TOPDIR to /usr/share, or TZDIR to /usr/share/zoneinfo, 
I should be able to fix it.

But no!  It still doesn't work, and the reason is, my user
environment doesn't have the TZ environment variable set; I'm
assuming that the system's default time zone will be used.
And, out of the box, the tzcode distribution assumes that the
local time zone is defined by a file 'localtime' *in TZDIR*; that
is, it essentially assumes that TZDEFAULT is $TZDIR/localtime.
But some (perhaps even many) systems put it in /etc/localtime.
That's where my (MacOS) system puts it, and a lot of Linux
systems put it there, too.

The upshot is that on such a system, if you compile and use
localtime.c straight out of the tzcode distribution, it won't
find your localtime file, and will end up falling back to UTC
unless TZ is set.

Since the Makefile already lets you set your own version of TZDIR
(overriding the setting in tzfile.h), I think it makes sense to
do the same thing for TZDEFAULT.  Patch attached.

With this patch in place, and with the Makefile edited to say

	TZDEFAULT = "/etc/localtime"

fresh compiles of localtime.o correctly find my system's
localtime file, and the lt program finally prints local time,
as expected.

(This tweak to TZDEFAULT's usage helps the extraction case --
that is, when the code tries to fetch the default zone, but not
necessarily the tz file building case.  I'm not sure whether
'make install' will do the right thing when TZDEFAULT is set, but
it definitely doesn't do the right thing if DESTDIR and TZDEFAULT
are both set.  Is using DESTDIR supported?  The Makefile should
probably document it if so.)

Diagnosing problems involving misconfigured TZDIR and TZDEFAULT
variables can be surprisingly difficult.  The localtime code
doesn't have any way of telling you it's having trouble finding
tz files in general, or the localtime file in particular.
I'll address that issue in a separate thread.

					Steve Summit
					scs at eskimo.com
-------------- next part --------------
--- a/Makefile	2017-10-01 20:23:52.000000000 -0400
+++ b/Makefile	2017-12-07 22:34:51.000000000 -0500
@@ -46,14 +46,24 @@
 
 TOPDIR=		/usr/local
 
-# "Compiled" time zone information is placed in the "TZDIR" directory
+# "Compiled" time zone information lives in the "TZDIR" directory
 # (and subdirectories).
+# It is placed there by 'make install' in this Makefile,
+# and it is sought there by the tz-using code in this package.
 # Use an absolute path name for TZDIR unless you're just testing the software.
 # TZDIR_BASENAME should not contain "/" and should not be ".", ".." or empty.
 
 TZDIR_BASENAME=	zoneinfo
 TZDIR=		$(TOPDIR)/etc/$(TZDIR_BASENAME)
 
+# By default, the default local time zone is taken from the file "localtime"
+# in TZDIR.  Or you can specify a different file by adjusting the definition
+# of TZDEFAULT, or cause it to be looked for somewhere other than TZDIR by
+# setting TZDEFAULT to an absolute path.  (For example, it's typically
+# "/etc/localtime" for MacOS, BSD, and some versions of Linux.)
+
+TZDEFAULT = "localtime"
+
 # Types to try, as an alternative to time_t.  int64_t should be first.
 TIME_T_ALTERNATIVES= int64_t int32_t uint32_t uint64_t
 
@@ -396,7 +406,7 @@
 #MAKE=		make
 
 cc=		cc
-CC=		$(cc) -DTZDIR=\"$(TZDIR)\"
+CC=		$(cc) -DTZDIR=\"$(TZDIR)\" -DTZDEFAULT=\"$(TZDEFAULT)\"
 
 AR=		ar
 


More information about the tz mailing list