[comp.unix.wizards] Daylight Savings Time: how to fix ctime.c

Makey@LOGICON.arpa (Jeff Makey) (03/17/87)

Those of you with UNIX source who plan to fix your ctime routine so it
knows about the 1987+ daylight savings time rules should be interested
in the following information about daylight time in the United States.

    before 1967     no daylight time at all
    1967 -> 1973    last Sunday in April -> last Sunday in October
    1974            first Sunday in January -> last Sunday in October
    1975            last Sunday in February -> last Sunday in October
    1976 -> 1986    last Sunday in April -> last Sunday in October
    beginning 1987  first Sunday in April -> last Sunday in October

Note that every UNIX system I have ever seen (including SVR2 and
4.2BSD) mistakenly thinks that daylight time in 1974 ends on the last
Sunday in November.  My evidence to the contrary is on page 741 of the
1984 edition of The World Almanac and Book of Facts and in a small
article on page 3 of the 27 October 1974 edition of the Los Angeles
Times (as recorded on microfilm at the San Diego city library).  Check
it yourself if you don't beleive me.

The following data structure is useful for determining when daylight
savings time is in effect in the United States.  Any future changes
should be simple and efficient.

struct dstab {
	int	dayyr;
	int	daylb;
	int	dayle;
} usdaytab[] {
	{ 1987,	96,	303 },	/* first Sun in Apr to last Sun in Oct */
	{ 1976,	119,	303 },	/* last Sun in Apr to last Sun in Oct */
	{ 1975,	58,	303 },	/* last Sun in Feb to last Sun in Oct */
	{ 1974,	5,	303 },	/* first Sun in Jan to last Sun in Oct */
	{ 1967,	119,	303 },	/* last Sun in Apr to last Sun in Oct */
	{ 0,	400,	0 }	/* no daylight time at all */
};

The order (years are decreasing) of the entries in the table is
important.  In your code, use something like the following to select
the appropriate table entry:

	struct dstab *ds;
	for (ds = usdaytab; ds->dayyr; ds++)
		if (year >= ds->dayyr)
			break;

Those of you with 4.2BSD will notice a for loop very much like this one
in localtime().  The important difference is the ">=" rather than the
"==" in the if statement.

You have a little less than 3 weeks to change ctime and relink programs
that use it.  I used what(I) on 4.2BSD to find about 70 executables
that are affected.

                         :: Jeff Makey
                            Makey@LOGICON.ARPA

P.S.  Any requests for complete ctime sources will be forwarded to
      /dev/null.

guy%gorodish@Sun.COM (Guy Harris) (03/17/87)

>The following data structure is useful for determining when daylight
>savings time is in effect in the United States.  Any future changes
>should be simple and efficient.

No changes that require you to modify "ctime.c" can possibly be
"simple".

>P.S.  Any requests for complete ctime sources will be forwarded to
>      /dev/null.

They should be forwarded to some "mod.sources" archive, instead.  The
code developed by Arthur Olson and others reads the rules from a
*file*, which means you can change them without recompiling
*anything*.  The DST tables included therein correctly specify the
U.S.A DST rules and the Australian rules (at least the rules as of
the last time Robert Elz checked - they seem to be rather subject to
change); they include what we think are the correct European rules
starting in 1986 or so (if anybody wants to supply rules for earlier
years, please do so and send them to Arthur at seismo!elsie!ado), and
come close to the correct Canadian rules (except for Saskatchewan,
which does not observe DST) assuming they follow the US's lead.
(They even include something pretty close to a Solar time table for
1987 in Riyadh, so that old comment in the "ctime" code need no
longer apply....)

jerryp@tektools.TEK.COM (Jerry Peek) (03/19/87)

In article <4992@brl-adm.ARPA> Makey@LOGICON.arpa (Jeff Makey) writes:
> Those of you with UNIX source who plan to fix your ctime routine so it
> knows about the 1987+ daylight savings time rules should be interested
> in the following information about daylight time in the United States.
> 
>     before 1967     no daylight time at all
>     1967 -> 1973    last Sunday in April -> last Sunday in October
>     1974            first Sunday in January -> last Sunday in October
>     1975            last Sunday in February -> last Sunday in October
>     1976 -> 1986    last Sunday in April -> last Sunday in October
>     beginning 1987  first Sunday in April -> last Sunday in October

Don't forget about *local* variations in DST rules.  I don't know how many
places are like the town where I grew up (Los Alamos, NM)... but my town went
on Daylight time during the summers, even when the rest of the state didn't.
Once the national DST laws took effect, I think Los Alamos just followed along.

[It was a weird town anyway... must be all that nuclear radiation stuff. :-)]

--Jerry Peek, Tektronix, Inc.
US Mail:      MS 74-900, P.O. Box 500, Beaverton, OR 97077
uucp-style:   {allegra,decvax,hplabs,ihnp4,ucbvax}!tektronix!tektools!jerryp
Domain-style: jerryp@tektools.TEK.COM
Phone:        +1 503 627-1603

devine@vianet.UUCP (Bob Devine) (03/19/87)

In article <4992@brl-adm.ARPA>, Makey@LOGICON.arpa (Jeff Makey) writes:
> Those of you with UNIX source who plan to fix your ctime routine so it
> knows about the 1987+ daylight savings time rules should be interested
> in the following information about daylight time in the United States.

  A better way exists.  Hardcoding a change into the "ctime" library
is painful (tracking down and changing the affected programs is no fun)
and the changes never stop.  There have been proposals for changes in
the Daylight Saving Time rules for Presidential election years in the
US and individual states may change the rules locally.

  Check mod.sources archives for a file-based public-domain version
of how to deal with timezones and seasonal time changes for many
countries (original author is Arthur Olson; reachable at elsie!ado).

Bob Devine

>     before 1967     no daylight time at all
>     1967 -> 1973    last Sunday in April -> last Sunday in October
>     1974            first Sunday in January -> last Sunday in October
>     1975            last Sunday in February -> last Sunday in October
>     1976 -> 1986    last Sunday in April -> last Sunday in October
>     beginning 1987  first Sunday in April -> last Sunday in October

  The "before 1967" rule is plainly wrong.  Also, each of the above
rules has major exceptions!

Makey@LOGICON.arpa (Jeff Makey) (03/20/87)

Guy Harris <guy%gorodish@Sun.COM> and Bob Devine <devine@vianet.uucp>
have suggested the use of a version of localtime() that was posted to
mod.sources a couple of weeks ago.  This version keeps the daylight
savings time (DST) rules in a special disk file rather than having them
linked into each executable image.  Any future (or local) changes to
the DST rules can, therefore, be easily made without recompiling 70+
programs.

Unfortunately, such an implementation sacrifices execution speed for
the sake of rule flexibility.  Very few UNIX systems really need to
know about DST rules for more than one locality, and Congress seems to
have more important things to do than change the DST rules very often.
The changes I posted will benefit anyone who would rather spend a few
hours recompiling some programs once every few years than have to wait
for "date" to find some file buried in the bowels of the hierarchy.  It
may not really be time-efficient, but it helps keep the frustration
level down when the system is heavily loaded.

Getting both flexibility and execution speed would require intelligent
use of System V's shared memory (great for us BSD types! :-).  Don't
hold your breath.

Aslo, Jerry Peek <jerryp@tektools.TEK.COM> warned about local
variations in DST.  The rules given in my original posting are those
promulgated by Congress.  While most of the United States follows those
rules, your local rules may differ.

                             :: Jeff Makey
                                Makey@LOGICON.ARPA

guy@gorodish.UUCP (03/20/87)

> Unfortunately, such an implementation sacrifices execution speed for
> the sake of rule flexibility.

Oh, really?

	gorodish$ time /bin/date	# 4.2BSD version of "ctime"
	Fri Mar 20 02:11:32 PST 1987

	real	0m0.10s
	user	0m0.01s
	sys	0m0.03s
	gorodish$ time /bin/date
	Fri Mar 20 02:11:35 PST 1987

	real	0m0.10s
	user	0m0.00s
	sys	0m0.06s
	gorodish$ time /bin/date
	Fri Mar 20 02:11:38 PST 1987

	real	0m0.10s
	user	0m0.00s
	sys	0m0.08s
	gorodish$ time /usr/5bin/date	# S5 version of "ctime"
	Fri Mar 20 02:11:43 PST 1987

	real	0m0.41s
	user	0m0.01s
	sys	0m0.11s
	gorodish$ time /usr/5bin/date
	Fri Mar 20 02:11:46 PST 1987

	real	0m0.10s
	user	0m0.00s
	sys	0m0.10s
	gorodish$ time /usr/5bin/date
	Fri Mar 20 02:11:48 PST 1987

	real	0m0.10s
	user	0m0.00s
	sys	0m0.08s
	gorodish$ time ./date		# Olson version of "ctime"
	Fri Mar 20 02:11:51 PST 1987

	real	0m0.20s
	user	0m0.01s
	sys	0m0.08s
	gorodish$ time ./date
	Fri Mar 20 02:11:53 PST 1987

	real	0m0.15s
	user	0m0.00s
	sys	0m0.08s
	gorodish$ time ./date
	Fri Mar 20 02:11:54 PST 1987

	real	0m0.11s
	user	0m0.00s
	sys	0m0.06s
	gorodish$ 

The CPU time differences seem insignificant.  I suspect if you did a
more rigorous test, the differences would be statistically
insigificant.  Other than the startup transient (most likely due to
pulling the file into the buffer cache), the real time differences
were minor as well.  (I'd say that large startup transient for
"/usr/5bin" reflected the fact that the program is being fetched via
NFS, except that both the test version of "date" *and* its data files
are being fetched over NFS here.)

Other tests I've done (a test doing one call to "ctime" on the current time,
and a test doing lots of them) show much the same thing.

Less speculation on what will or won't be expensive, and more data,
please!  Just because it "makes sense" that X will be more expensive
than Y doesn't mean it *will* be.

There are places (Australia, for one) where rule changes *do* seem to
be frequent.  Given the small extra cost of the file-based DST
scheme, were I in Australia I would be more than willing to use it to
avoid having to recompile tons of software (or recompile *and* send
out updates, in the case of a vendor, or wait for said vendor to send
out the updates, in the case of a binary-only customer).

jas@rtech.UUCP (03/20/87)

Jeff Makey (Makey@LOGICON.arpa) writes about timezone and daylight savings
time management:

> Unfortunately, [keeping the timezone and DST tables on disk] sacrifices
> execution speed for the sake of rule flexibility....  [I'd rather not]
> have to wait for "date" to find some file buried in the bowels of the
> hierarchy....
> 
> Getting both flexibility and execution speed would require intelligent
> use of System V's shared memory (great for us BSD types! :-).

Actually, a shared library seems more appropriate (equally great for
us BSD types).

Another thought:  load the tables into an environment variable at login
time, a la TERMCAP.  (Telling all UNIX users in Arizona, Western Europe,
Afghanistan, etc. to recompile n UNIX utilities and m locally written
programs and k software packages delivered by an outside vendor just
doesn't seem like an option.)
-- 
Jim Shankland
 ..!ihnp4!cpsc6a!\
                  rtech!jas
..!ucbvax!mtxinu!/

guy@gorodish.UUCP (03/22/87)

>Actually, a shared library seems more appropriate (equally great for
>us BSD types).

No, because it would be a bigger pain to replace a shared library if
the rules change.

Another "no" to both is that shared libraries *and* shared memory
segments are extensions to the SVID.  Some implementations may have
difficulty implementing either or both, due to hardware limitations,
and may in fact not implement them.

(Note that some future BSD release may implement "mmap", which can
give you both shared data *and* shared libraries; some people who
started with 4.2BSD or 4.3BSD kernels have added various flavors of
"mmap", S5 shared memory, or shared libraries to them.)

>Another thought:  load the tables into an environment variable at login
>time, a la TERMCAP.

If you loaded them in binary form, it would be fun to watch people
use the "(print)env" command(s).  If you loaded them in ASCII string
form, it would chew up a fair bit of your argument list space (thus
significantly reducing the number of bytes of arguments you could
pass to commands).  I'd also want to see actual timing tests before I
believed that this was a net performance win (remember, even if you
fork and exec a program that *doesn't* do time conversions, you still
have to copy the environment).

(I'm still not sure why people are trying to come up with
alternatives to code that's publicly available and that seems, at
least in my tests, to have adequate performance.)