Time for UNIX
Larry Reznick
Midnight, Thu Jan 1, 1970 is the traditional beginning
of the UNIX
epoch. UNIX keeps track of time as the number of seconds
elapsed since
that date, Greenwich Mean Time (GMT). UNIX stores the
seconds as a
32-bit offset from that date, where 0 is that date.
Using 32 bits,
UNIX can represent a range of 4,294,967,296 seconds,
which amounts
to 136 years, 36 days, 6 hours, 28 minutes, and 16 seconds.
The program
in Listing 1 shows that the minimum date representable
(-2,147,483,648)
is Fri Dec 13, 1901, at 8:45:52 pm and the maximum (2,147,483,647)
is Tue Jan 19, 2038, at 3:14:07 am. Only about 44 more
years remain
before UNIX has to set a new epoch.
This 32-bit number (the seconds offset from the beginning
of the epoch)
is used throughout UNIX operations. It figures in the
time stamping
of files, in the process and login time stamps, and
in all other time
calculations. The ANSI C Standard borrowed this idea
for the time_t
data type, so any C program written with the standard
library's time
functions is using the UNIX epoch format. Other systems
may use a
different epoch -- for instance, MSDOS and derivatives
use midnight,
Jan 1, 1980 instead -- but the idea is the same.
Time is an important aspect of UNIX operations because
UNIX systems
are often left on around the clock to take advantage
of background
processing and deferred processing. cron doesn't work
without
the real time clock operating properly, and for the
clock to run properly
the system administrator must understand how UNIX treats
local time
zones, daylight savings time, and holidays.
Local Time Zones
Each user has an individual time zone setting stored
in the TZ
environment variable. This variable's initial setting
derives from
the system-wide setting in the /etc/TIMEZONE file. TZ
can hold a simple value composed of two parts, but typically
the value
is composed of at least three parts: the three-letter
abbreviation
for the standard time zone, the number of hours offset
from GMT to
that time zone, and the three-letter abbreviation for
the zone's daylight
savings time. For example, PST8PDT means that Pacific
Standard
Time is eight hours away from GMT and Pacific Daylight
Time applies.
A system in New York is only five hours away from GMT,
so it would
use EST5EDT.
Hour offsets can be either positive or negative. One
adds eight hours
to PST to get GMT. At a site east of GMT, one would
subtract hours
to get to GMT. For instance, Middle European Time, also
known as Central
European Time, is MET-1 DST, Hong Kong time is HKT-8,
and Japan time is JST-9. (Add -1, -8, and -9 hours,
respectively,
to local time at these locations to get GMT.) The offset
can include
minutes, and even seconds, if necessary. Hours, minutes,
and seconds
are separated with colons. For instance, Newfoundland
and parts of
Australia use half-hour offsets from GMT. Newfoundland's
is NST3:30NDT.
UNIX assumes that daylight savings time is one hour
different from
the usual local offset. If that isn't true for your
location, you
can overide the default with an additional offset value
following
the daylight savings time abbreviation.
Each user can have an individual time zone setting.
(This is handy
for people who commonly login to the system from remote
sites.) You
can set the TZ variable from within the user's own .profile
files under Bourne Shell (sh) or Korn Shell (ksh), or
within the .login
files if you're using C-Shell (csh). Once TZ is reset,
all
time stamps are adjusted to the new time zone, yet other
people with
different time zone settings would see their own zone-adjusted
times.
Try it! Create a file, then look at a long listing showing
the time
stamp of that file. Change your TZ variable's setting.
Be
sure to export TZ if you're using sh or ksh.
Then look at a long listing of that file. The time stamp
has adjusted
to the new time zone. You can reset your TZ to the system's
standard by executing the /etc/TIMEZONE script. Use
the command
. /etc/TIMEZONE in sh or ksh. For csh,
you'll need to manually execute the TZ setting shown
in /etc/TIMEZONE
by using the setenv command.
Daylight Savings Time
One great problem in time-keeping today is daylight
savings time (DST).
Different regions have different rules and these rules
are often inconsistent.
The general rule now in the United States is to add
one hour to the
clock at 2 am on the first Sunday in April, and take
that hour back
at 2 am on the last Sunday in October. Of course, it
wasn't always
this way. Before 1974, DST started on the last Sunday
in April. In
1974, Presidential decree set the start date back to
January. In 1975,
DST started in February. From 1976 to 1986 it started
on the last
Sunday in April. In 1987 it was pushed back to the first
Sunday in
April, where it is today.
If you think that sounds complicated be warned that
it gets worse.
Some countries change in different months, on different
days of the
week, and at different times of the day. Some countries
don't use
DST. According to the rules I've found, the People's
Republic of China
turns back to standard time in September, not October,
while the Republic
of Korea changes to DST in May, not April. European
countries appear
to change in March and September, but some change at
2 am, and some
at 3 am. Southern hemisphere countries must reverse
their change months.
Some parts of Australia had variations during the 1970s
but now seem
to revert to standard time in March. Other parts of
Australia don't
use DST. New South Wales had several variations in the
1980s but has
settled down to starting DST in October and ending it
in March. Brazil
changes on Saturdays instead of Sundays.
Given these examples, a system administrator clearly
can't set the
DST date once and never look at it again. New UNIX site
installations
may require someone to look at the local conventions
and adjust the
system's clock to seasonal changes. Existing UNIX installations
must
occasionally update their settings when the government
declares a
new time change.
The simplest example of a TZ setting is one without
daylight
savings time, such as JST-9. Japan Standard Time (JST-9)
is nine hours east of GMT. (Japan doesn't observe Daylight
Savings
Time.) In the United States, PST8PDT, Pacific Standard
Time
is eight hours west of GMT and has a daylight time abbreviation
without
a number. Without a number following the daylight time
abbreviation
(PDT), the system assumes that the daylight time is
offset
one hour from the standard time. You may specify a DST
absolute hour
offset if you need one. For example, PST8PDT7 explicitly
requires
that daylight savings time in the Pacific zone be seven
hours away
from GMT.
I have yet to determine how the system identifies when
in the year
to change to daylight savings time. The TZ variable
definition
includes a mechanism for explicitly citing only one
year. After the
DST abbreviation and its own optional hour offset, you
may include
a comma followed by a starting date and time, and another
comma followed
by an ending date and time. On the starting date, at
the specified
time, the system applies the DST offset. When the ending
date and
time come, the standard offset is restored. For example,
PST8PDT,92/2:00:00,302/2:00:00
A start time comes after the first comma. The number
92 refers to
April 3, the first Sunday in April in 1994. (This 92
is determined
from Table 1.) Following the 92 is a slash, which separates
the day
number from the time to start the PDT change: 2 am.
Another comma
signals the end time. The 302, again from Table 1, refers
to October
30, the last Sunday in October in 1994. On that date
at 2 am, PDT
is turned off and the system returns to PST. Changing
at 2 am is the
default, so the line could have been:
PST8PDT,92,302
The problem with this Table 1 method is that in 1995
the Sundays will fall on different dates. Daylight savings
time will
begin on day 91 (instead of 92), and end on day 301
(instead of 302).
So a system administrator using this method must change
the date numbers
annually.
(There are 14 possible calendars -- seven plain years
with January
1 on each day of the week and seven leap years with
January 1 on each
day of the week. A system administrator could create
the 14 possible
variations as separate files, but would still have to
enable the appropriate
one each year. I can imagine a cron job using my day-of-the-week
script ("Which Day of the Week Is This?,"
Jul/Aug 1993 Sys
Admin, vol. 2, no. 4, p. 79) that runs every January
1 and enables
the appropriate variation in /etc/TIMEZONE. Or maybe
one could
change the /etc/TIMEZONE script itself, making it far
more
sophisticated so that it can figure the local time directly
at every
login. I don't find this an elegant solution, though.
There still
exists the problem of modifying all 14 variations to
accommodate a
national or local daylight savings time change.)
Somebody came up with a better way. I've found that
if I don't explicitly
name the DST start and end dates my system knows to
start on the first
Sunday in April and end on the last Sunday in October.
I didn't tell
it to do that, so the method must exist somewhere. My
Esix SVR4 system
has a /usr/lib/locale/TZ directory containing a set
of files
that identify many time zones and their DST variations.
I found some
documentation for this in zic(1M), which stands for
zone information
compiler. There are seven files in zic containing data
for
major regions of the world. Table 2 reviews the contents
of those
files.
These files contain two kinds of tables, known as rules
and zones,
and may contain links that identify variations in zone
names. The
tables make it easy to track and modify time zone variations.
The
zic program reads these files and produces very small
compiled
files and occasionally some directories that represent
the rules in
some system-usable form.
There's only one problem. I can't find where the zic's
files
get installed so the system can use them. The zic man
page
doesn't say. The man page refers to a standard directory,
/usr/share/lib/zoneinfo, where the compiled files will
reside,
but that directory doesn't exist on a newly installed
system and running
zic doesn't create it. If the directory doesn't exist,
where
are the files that drive newly installed systems? I
searched through
my system using the names that zic created but I couldn't
find any originals with those file names. So, I'm stumped.
I know my system knows the appropriate time to change
to DST. I know
the system's time change corresponds with the information
contained
within the appropriate /usr/lib/locale/TZ table file.
I don't
know how it knows that. I don't know where to install
the new files
created by zic if I need to change or add to the rules,
or
how to tell the system to use the newly created files.
Because zic
has an option to put the files into a directory other
than /usr/share/lib/zoneinfo,
I assume there is some way to tell the system which
directory to use.
(This method would be similar to debugging terminfo
files,
where you can identify a specific directory for testing
new terminfo
definitions without fouling up the rest of the system.)
No man pages
I've found yet answer any of these questions about zic.
If you know the secrets of the time zone tables used
by zic,
or if you have found or will write more thorough documentation
for
using these files, please contact Sys Admin.
Accounting Holidays
The first time I ran accounting on UNIX I discovered
an error message
about an undocumented /etc/acct/holidays file. This
file defines
the current year, the hour and minute when prime time
system usage
begins, the hour and minute when non-prime time usage
begins, and
the holidays recognized by the system site.
At least five accounting programs use the holidays file:
acctcms(1M),
acctcon(1M), acctcon1(1M), acctprc(1M), and
acctprc1(1M). The runacct(1M) script tests to see
if acctcon creates an error log file. That log file
is created
if some process named pnpsplit fails. This pnpsplit,
most likely a compiled function named for Prime time/Non-Prime
time
parsing, probably reads, parses, and validates the holidays
file,
preparing the holidays data for further use by other
parts of those
programs. I've deduced this from error messages within
the five compiled
accounting programs. There is no documentation for pnpsplit
and my system contains no source code associated with
it. (I refuse
to disassemble acctcon.)
There is a maximum number of holiday entries because
the error messages
ask the user to recompile pnpsplit and increase a constant
named NHOLIDAYS. Unfortunately, this isn't easy to do
when
the source code is unavailable and I have no idea what
the maximum
NHOLIDAYS is set to. However, I know that at least eight
holidays
are supported because that's how many are listed in
my copy of /etc/acct/holidays.
Because this holidays file isn't documented except by
the comments
in the file, I'll try to document the file format here:
1. Comments begin with an asterisk (*) and extend
to the end of the line.
2. The first uncommented line contains three tab-separated
numbers. Leading white space is ignored.
a. The first number is the current year expressed as
a four-digit number, such as 1994.
b. The second number is the time when prime time starts
expressed as a four-digit number representing a 24-hour
clock. For
instance, use 0800 to mean 8:00 am.
c. The third number is the time when non-prime time
starts expressed as a four-digit number representing
a 24-hour clock.
For instance, use 1800 to mean 6:00 pm.
The line containing all three examples would look like
this:
1994 0800 1800
3. The remaining uncommented lines contain the month,
a slash (/),
and the day of the holiday followed optionally by at
least one tab
and any comments about the date, such as the name of
the holiday.
Each holiday requires a new line. New Year's Day would
look like this:
1/1 New Year's Day
Every date listed in the /etc/acct/holidays file
is presumably treated as non-prime time, and so are
times on all other
dates between the non-prime start time and the prime
start time.
Here's the problem for the system administrator: this
holidays file
has to be changed every year. Certain holidays fall
on specific dates
despite the day of the week, such as New Year's Day,
Christmas Eve,
and Christmas Day. These holidays never need changing.
But other holidays
fall on certain weekdays, such as Memorial Day, Labor
Day, and Thanksgiving
Day. The dates for these holidays will be different
every year.
I propose a script that cron can run once a year. This
script
reads a configuration file containing a table that identifies
facts
about the holiday, which could be the specific month
and day or could
be some designation such as the fourth Thursday of November.
The advantage
of this configuration file is in uniformly identifying
different holidays
for different locales. The script analyzes the current
year's calendar,
possibly using my day-of-the-week script, and updates
the /etc/acct/holidays
file indentifying the current year and the holiday dates
for that
current year. If you have the script, or wish to write
the script,
to handle this problem, contact Sys Admin.
About the Author
Larry Reznick has been programming professionally since
1978. He is currently
working on systems programming in UNIX, MS-DOS, and
OS/2.
He teaches C language courses
at American River College and at National University
in Sacramento.
He can be reached via email at:
rezbook!reznick@csusac.ecs.csus.edu.
|