TZ Rationalization Requested

Guy Harris guy at rlgvax.UUCP
Sat Mar 10 12:35:26 AEST 1984


The question was "why do USG UNIX systems get the timezone information
from an environment variable TZ, which is only read if you remember to
call "tzset()", while it comes from a system call in V7 and descendants?"
and "has anyone else heard a better reason to do it this way?"

Well, the only reason I can think of to do it this way, other than the
ability you mentioned to set the time zone on a per-session basis, is the
ability to change the time zone without doing a system generation.

I don't know that this is a better reason to do it this way; on the other hand,
what you've given is a reason to do it a better way.

Suggested way - thanks to Microsoft, who did it at least partially this way
on their S3-base Xenix, which also keeps around the old V7 system call
"ftime" to get it from the kernel.

1) GET RID OF THE REQUIREMENT TO EXPLICITLY CALL "tzset"!  If the extra
CPU cycles spent asking for the timezone on every call to "ctime" bothers
you, set a static flag once you've called "tzset", and only call it from
within "ctime" (and "localtime" and the like) if the flag is zero.  There's
not much point in calling "tzset" twice in a process, anyway, considering
it requires a bit of contortion to change the processes' environment from
within the process (chase down "environ" for the "TZ=" entry and replace it).
"tzset" can still be left around; you may just want the timezone and DST flag
values, and you may not want to make a system call (for reasons of portability
to S5 and previous USG versions).

2) Have "tzset" make the system call if it doesn't find TZ in the environment,
instead of defaulting to EST.  Keep the old V7 table of time zone names, and
have it search that table after the system call to find the names.

In effect, you're merging the V7 and USG code, and keeping the USG call
interface (which is downward (upward? whatever) compatible with V6, but not
compatible with V7.  Too bad they couldn't make up their mind...).  If TZ
is not set, things don't break, they just get the time zone from a nice
central source.  TZ is only set if somebody explictly wants to override it.
As for the question of doing sysgens, that's a red herring.  In USG UNIX, you
have to do sysgens *anyway*, in order to set kernel parameters and (this is
the key point) *the system's network node name*.  So it's not practical to
just build one binary and stick it on several machines without change
*anyway*.  I don't know if anybody builds a common kernel and then patches
the "utsname" structure *ex post facto* (we do), but one could patch a timezone
information structure in the same way.

Or, if that's too kludgy, take a leaf from Berkeley's book - specifically,
the book labelled "UNIX Programmer's Manual, 4.2 Berkeley Software
Distribution, Virtual VAX-11 Version" and the leaf labelled "GETTIMEOFDAY(2)".
The "gettimeofday" system call takes two pointers to structures as arguments,
and fills those structures in: a structure containing the time of day (a
longword of seconds and a longword of microseconds) and a structure containing
the timezone information (offset in minutes west of Greewich and daylight
savings time flag). "settimeofday" takes two pointers to similar structures as
arguments; the contents of the first structure sets the system time, and if
the pointer to the second structure is non-NULL its contents set the timezone
information and DST flag (the fact that the latter pointer may be NULL and
causes the system to leave the timezone information alone is undocumented -
add another one to the long list of undocumented and useful and worthy-of-
official-support-and-documentation features in UNIX, both Bell and Berkeley).
They did the same thing with the host name, by the way; "gethostname" and
"sethostname" system calls exist.

The requirement that an environment variable be set in order for the system
to understand time zones sucks.  The person who made it a requirement obviously
never thought that somebody would actually put something in the "shell"
field in the password file, so obviously you can set TZ in "/etc/profile"
(which gets executed by the USG Bourne shell, when run as a login shell,
just before your ".profile" - a good idea, by the way) and it'll be set for
everybody except for stuff run from "/etc/rc" - set it there, and you're home
free, right?  WRONG!  We frequently set up people who run our office automation
software with that system as their login shell, and the top-level shell
of that software doesn't know "/etc/profile" from Adam.  There *are* two
ways of fixing this:

1) make their "login shell" a shell file (yes, believe it or not, this is
supported by the V7, 4.xBSD, S3, and S5 "login program) which sets TZ and
runs the program in question.  This means, of course, that when you install
a system it's *one more place* where you have to remember to change TZ if
it's in a different time zone...

2) fix "login" so that it adds things like HOME to the environment passed
to it, rather than creating a new environment *ab initio*, and make your
lines in "/etc/inittab" look like

	2:h0:c:env TERM=vt100 TZ=PST8PDT /etc/getty ttyh0 d

which is the solution we chose, as it permits us to put TERM into the
environment automatically as well; the authors of a lot of the UNIX code work
for an organization that places heavy emphasis on dial-up use of UNIX
(the reasons for this should be obvious when you consider the main source
of revenue for that organization :-)), where setting TERM automatically
is usually useless, but most of us work at sane places with 9600 baud or
faster hardwired terminals, and port "/dev/ttyh0" is going to be a VT100
unless and until somebody moves the VT100.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy



More information about the Comp.unix.wizards mailing list