Go backward to Business Days. Go up to Date Arithmetic.

Time Zones
----------

Time zones and daylight savings time are a complicated business.  The
conversions to and from Julian and Unix-style dates automatically
compute the correct time zone and daylight savings adjustment to use,
provided they can figure out this information.  This section describes
Calc's time zone adjustment algorithm in detail, in case you want to
do conversions in different time zones or in case Calc's algorithms
can't determine the right correction to use.

Adjustments for time zones and daylight savings time are done by `t
U', `t J', `t N', and `t C', but not by any other commands.  In
particular, `<may 1 1991> - <apr 1 1991>' evaluates to exactly 30 days
even though there is a daylight-savings transition in between.  This
is also true for Julian pure dates: `julian(<may 1 1991>) -
julian(<apr 1 1991>)'.  But Julian and Unix date/times will adjust for
daylight savings time: `julian(<12am may 1 1991>) - julian(<12am apr 1
1991>)' evaluates to `29.95834' (that's 29 days and 23 hours) because
one hour was lost when daylight savings commenced on April 7, 1991.

In brief, the idiom `julian(DATE1) - julian(DATE2)' computes the
actual number of 24-hour periods between two dates, whereas `DATE1 -
DATE2' computes the number of calendar days between two dates without
taking daylight savings into account.

The `calc-time-zone' [`tzone'] command converts the time zone
specified by its numeric prefix argument into a number of seconds
difference from Greenwich mean time (GMT).  If the argument is a
number, the result is simply that value multiplied by 3600.  Typical
arguments for North America are 5 (Eastern) or 8 (Pacific).  If
Daylight Savings time is in effect, one hour should be subtracted from
the normal difference.

If you give a prefix of plain `C-u', `calc-time-zone' (like other date
arithmetic commands that include a time zone argument) takes the zone
argument from the top of the stack.  (In the case of `t J' and `t U',
the normal argument is then taken from the second-to-top stack
position.)  This allows you to give a non-integer time zone
adjustment.  The time-zone argument can also be an HMS form, or it can
be a variable which is a time zone name in upper- or lower-case.  For
example `tzone(PST) = tzone(8)' and `tzone(pdt) = tzone(7)' (for
Pacific standard and daylight savings times, respectively).

North American and European time zone names are defined as follows;
note that for each time zone there is one name for standard time,
another for daylight savings time, and a third for "generalized" time
in which the daylight savings adjustment is computed from context.

     YST  PST  MST  CST  EST  AST    NST    GMT   WET     MET    MEZ
      9    8    7    6    5    4     3.5     0     -1      -2     -2

     YDT  PDT  MDT  CDT  EDT  ADT    NDT    BST  WETDST  METDST  MESZ
      8    7    6    5    4    3     2.5     -1    -2      -3     -3

     YGT  PGT  MGT  CGT  EGT  AGT    NGT    BGT   WEGT    MEGT   MEGZ
     9/8  8/7  7/6  6/5  5/4  4/3  3.5/2.5  0/-1 -1/-2   -2/-3  -2/-3

To define time zone names that do not appear in the above table, you
must modify the Lisp variable `math-tzone-names'.  This is a list of
lists describing the different time zone names; its structure is best
explained by an example.  The three entries for Pacific Time look like
this:

     ( ( "PST" 8 0 )    ; Name as an upper-case string, then standard
       ( "PDT" 8 -1 )   ; adjustment, then daylight savings adjustment.
       ( "PGT" 8 "PST" "PDT" ) )   ; Generalized time zone.

With no arguments, `calc-time-zone' or `tzone()' obtains an argument
from the Calc variable `TimeZone' if a value has been stored for that
variable.  If not, Calc runs the Unix `date' command and looks for one
of the above time zone names in the output; if this does not succeed,
`tzone()' leaves itself unevaluated.  The time zone name in the `date'
output may be followed by a signed adjustment, e.g., `GMT+5' or
`GMT+0500' which specifies a number of hours and minutes to be added
to the base time zone.  Calc stores the time zone it finds into
`TimeZone' to speed later calls to `tzone()'.

The special time zone name `local' is equivalent to no argument, i.e.,
it uses the local time zone as obtained from the `date' command.

If the time zone name found is one of the standard or daylight savings
zone names from the above table, and Calc's internal daylight savings
algorithm says that time and zone are consistent (e.g., `PDT'
accompanies a date that Calc's algorithm would also consider to be
daylight savings, or `PST' accompanies a date that Calc would consider
to be standard time), then Calc substitutes the corresponding
generalized time zone (like `PGT').

If your system does not have a suitable `date' command, you may wish
to put a `(setq var-TimeZone ...)' in your Emacs initialization file
to set the time zone.  The easiest way to do this is to edit the
`TimeZone' variable using Calc's `s T' command, then use the `s p'
(`calc-permanent-variable') command to save the value of `TimeZone'
permanently.

The `t J' and `t U' commands with no numeric prefix arguments do the
same thing as `tzone()'.  If the current time zone is a generalized
time zone, e.g., `EGT', Calc examines the date being converted to tell
whether to use standard or daylight savings time.  But if the current
time zone is explicit, e.g., `EST' or `EDT', then that adjustment is
used exactly and Calc's daylight savings algorithm is not consulted.

Some places don't follow the usual rules for daylight savings time.
The state of Arizona, for example, does not observe daylight savings
time.  If you run Calc during the winter season in Arizona, the Unix
`date' command will report `MST' time zone, which Calc will change to
`MGT'.  If you then convert a time that lies in the summer months,
Calc will apply an incorrect daylight savings time adjustment.  To
avoid this, set your `TimeZone' variable explicitly to `MST' to force
the use of standard, non-daylight-savings time.

By default Calc always considers daylight savings time to begin at 2
a.m. on the first Sunday of April, and to end at 2 a.m. on the last
Sunday of October.  This is the rule that has been in effect in North
America since 1987.  If you are in a country that uses different rules
for computing daylight savings time, you have two choices: Write your
own daylight savings hook, or control time zones explicitly by setting
the `TimeZone' variable and/or always giving a time-zone argument for
the conversion functions.

The Lisp variable `math-daylight-savings-hook' holds the name of a
function that is used to compute the daylight savings adjustment for a
given date.  The default is `math-std-daylight-savings', which
computes an adjustment (either 0 or -1) using the North American rules
given above.

The daylight savings hook function is called with four arguments: The
date, as a floating-point number in standard Calc format; a
six-element list of the date decomposed into year, month, day, hour,
minute, and second, respectively; a string which contains the
generalized time zone name in upper-case, e.g., `"WEGT"'; and a
special adjustment to be applied to the hour value when converting
into a generalized time zone (see below).

The Lisp function `math-prev-weekday-in-month' is useful for daylight
savings computations.  This is an internal version of the user-level
`pwday' function described in the previous section. It takes four
arguments: The floating-point date value, the corresponding
six-element date list, the day-of-month number, and the weekday number
(0-6).

The default daylight savings hook ignores the time zone name, but a
more sophisticated hook could use different algorithms for different
time zones.  It would also be possible to use different algorithms
depending on the year number, but the default hook always uses the
algorithm for 1987 and later.  Here is a listing of the default
daylight savings hook:

     (defun math-std-daylight-savings (date dt zone bump)
       (cond ((< (nth 1 dt) 4) 0)
             ((= (nth 1 dt) 4)
              (let ((sunday (math-prev-weekday-in-month date dt 7 0)))
                (cond ((< (nth 2 dt) sunday) 0)
                      ((= (nth 2 dt) sunday)
                       (if (>= (nth 3 dt) (+ 3 bump)) -1 0))
                      (t -1))))
             ((< (nth 1 dt) 10) -1)
             ((= (nth 1 dt) 10)
              (let ((sunday (math-prev-weekday-in-month date dt 31 0)))
                (cond ((< (nth 2 dt) sunday) -1)
                      ((= (nth 2 dt) sunday)
                       (if (>= (nth 3 dt) (+ 2 bump)) 0 -1))
                      (t 0))))
             (t 0))
     )

The `bump' parameter is equal to zero when Calc is converting from a
date form in a generalized time zone into a GMT date value.  It is -1
when Calc is converting in the other direction.  The adjustments shown
above ensure that the conversion behaves correctly and reasonably
around the 2 a.m. transition in each direction.

There is a "missing" hour between 2 a.m. and 3 a.m. at the beginning
of daylight savings time; converting a date/time form that falls in
this hour results in a time value for the following hour, from 3
a.m. to 4 a.m.  At the end of daylight savings time, the hour from 1
a.m. to 2 a.m. repeats itself; converting a date/time form that falls
in in this hour results in a time value for the first manifestion of
that time (*not* the one that occurs one hour later).

If `math-daylight-savings-hook' is `nil', then the daylight savings
adjustment is always taken to be zero.

In algebraic formulas, `tzone(ZONE, DATE)' computes the time zone
adjustment for a given zone name at a given date.  The DATE is ignored
unless ZONE is a generalized time zone.  If DATE is a date form, the
daylight savings computation is applied to it as it appears.  If DATE
is a numeric date value, it is adjusted for the daylight-savings
version of ZONE before being given to the daylight savings hook.  This
odd-sounding rule ensures that the daylight-savings computation is
always done in local time, not in the GMT time that a numeric DATE is
typically represented in.

The `dsadj(DATE, ZONE)' function computes the daylight savings
adjustment that is appropriate for DATE in time zone ZONE.  If ZONE is
explicitly in or not in daylight savings time (e.g., `PDT' or `PST')
the DATE is ignored.  If ZONE is a generalized time zone, the
algorithms described above are used.  If ZONE is omitted, the
computation is done for the current time zone.

See Reporting Bugs, for the address of Calc's author, if you
should wish to contribute your improved versions of `math-tzone-names'
and `math-daylight-savings-hook' to the Calc distribution.