[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: time zone and UTC issue



"J. B" <bakshi12@gmail.com> writes:

> My box is configured to the local time zone from beginning, both
> hwclock and system time.  But linux always favor hwclock to
> UTC. What is the advantage of doing that ?

Although time, timezones and clock setting are quite a simple topic it
seems to be major source of confusion for many people and many systems
are mis-configured, as can seen in this thread and as can be often
seen in E-mail time stamps.

I jumped into this thread somewhat late and wanted to write a couple
of sentences, but now this has become a little bit longer than
intended.

First, to reduce confusion, it is helpful to use good terminology and
to know what the meaning of used terms is.

1. Local time and UTC.

   I strongly dislike the term "local time".  There is no such thing
   as a local time or different local times in different locations (on
   earth).  There is only one global time.  What differs locally is
   only the /represantation/ of the time.  Nevertheless, I also
   sometimes use "local time" to mean "local time representation".
   Also, UTC is only /one/ possible representation for times.  It is
   special in that is "universal", i.e. it is used independent of
   location and doesn't have weird things like daylight saving times.
   Both, UTC and local time representation, express time as year,
   month, day, hour, minute, second, and (hopefully) timezone
   indicator.

2. System clock and system time.

   The system clock is a software clock driven by the Linux kernel and
   it defines the system time.  The system clock uses yet another time
   representation.  Although seemingly everybody states that Linux and
   Unix systems run their system clock in UTC, this is IMO not quite
   correct.  The system time, time stamps in Unix file systems, and
   time stamps exchanged between the Linux kernel and user space
   programs are representated as a POSIX time_t (or struct timeval or
   struct timespec).  This representation is only an integer number
   counting the seconds since the POSIX epoch (ignoring leap seconds).
   The timeval and timespec representation additionally give the
   microseconds and nanoseconds, respectively.  The POSIX epoch is a
   fixed point in time, usually given in UTC time representation and
   it is January 1, 1970 0:00:00 UTC.  The representation as a simple
   integer has several advantages:

   * It's very simple to advance the clock by one second.  No need to
     carry to the next unit after 60 seconds, 60 minutes, 24 hours,
     and so on.
   
   * It's very simple to calculate the difference between two times.
   
   * It's independent of local time representation and daylight saving
     rules.  It doesn't jump forth and back.
   
   When people say "The Linux kernel system time is always in UTC",
   what the really mean is that the kernel keeps a time representation
   that doesn't depend on any local timezone definitions, doesn't jump
   for daylight saving times and is based on a certain point in time
   (the epoch) which is usually expressed in UTC (although you could
   equally well define the epoch as "December 31, 1969 19:00:00
   Eastern Standard Time" because that is the /same/ time as
   1970-01-01 0:00:00 UTC).
   
   You can get the current kernel system time with the gettimeofday(2)
   or clock_gettime(2) system calls, or print it like this
   
       $ date +%s
       1354558752
       $ perl -e 'print time,"\n"'
       1354558754

   I think it's important to understand that you don't set the system
   clock to one time or another, you don't set it to "local time" nor
   to UTC.  You set it to "the current time" (or have it synchronized
   to "the current time" using NTP), since there is only one global
   time.  The representation used by the system clock is POSIX struct
   timespec and nothing else.

3. Hardware clock (aka. CMOS clock, BIOS clock or real time clock (RTC)).

   This is a clock that ticks independently from any operating system
   and even keeps running when the computer is turned off.  This clock
   represents its time as year-month-day-weekday-hour-minute-second so
   it can be set to any local time representation or to UTC.
   Unfortunately, it doesn't have information which representation it
   is set to nor if it currently is set to daylight saving time or
   not.  Without this information, you have to guess the meaning of
   the time you read from the hardware clock.  Therefore, it's best
   best to use UTC for this clock since that never has be adjusted for
   daylight saving time.  Otherwise, in multi-boot system each OS may
   adjust thue RTC by one hour resulting in wrong RTC time.

   This clock is normally not used in your Linux system, except when
   booting the system.  Early in the boot process the time is read
   from the hardware clock, its time representation is
   interpreted/guess (hopefully correct), the POSIX time_t calculated
   and the system time set from this.  After that, you can read and
   set the hardware clock using hwclock(8), but it's not used for
   other purposes.


Having the kernel system time represented as a POSIX time_t doesn't
mean the user has to deal with such time representations or with UTC
time representation.  There are library routines that, given a local
timezone description, can convert from your selected local time
representation to POSIX time_t and vice versa (localtime(3) and
mktime(3)).  In fact, there's not only one such local timezone
description, but there are many and each user[1] can choose which one
to use.  The default timezone is specified in /etc/localtime but you
can specify any other timezone using the TZ environment variable (my
default timezone is Europe/Berlin):

    $ date
    Mon Dec  3 19:19:20 CET 2012
    $ TZ=UTC                 date
    Mon Dec  3 18:19:23 UTC 2012
    $ TZ=America/Los_Angeles date
    Mon Dec  3 10:19:28 PST 2012
    $ TZ=America/Detroit     date
    Mon Dec  3 13:19:32 EST 2012
    $ TZ=Asia/Tokyo          date
    Tue Dec  4 03:19:36 JST 2012

You can also print the date for any time other than the current time
using date's -d option:

    $ # The POSIX epoch, expressed in Europe/Berlin timezone
    $ date -d@0
    Thu Jan  1 01:00:00 CET 1970
    $ # One hour later
    $ date -d@3600
    Thu Jan  1 02:00:00 CET 1970
    $ # The epoch expressed in UTC and Los Angeles time
    $ TZ=UTC date -d@0
    Thu Jan  1 00:00:00 UTC 1970
    $ TZ=America/Los_Angeles date -d@0
    Wed Dec 31 16:00:00 PST 1969

Using GNU date you can also easily convert any time representation
into a POSIX time_t, i.e. the kernels time representation for that
time:

    $ date -d"1967-01-31 17:27" +%s
    -92043180
    $ TZ=UTC date -d"1967-01-31 16:27" +%s
    -92043180
    $ # The time that many people celebrated as the begin of a new millenium
    $ TZ=America/New_York date -d"2000-01-01 0:00:00" +%s
    946702800

Almost all other tools that deal with times, also respect the default
timezone and the TZ environment variable:

    $ cd /tmp
    $ date; touch foo
    Mon Dec  3 19:21:09 CET 2012
    $ ls -l --time-style=full-iso foo
    -rw-r--r-- 1 urs urs 0 2012-12-03 19:21:09.973761852 +0100 foo
    $ TZ=UTC ls -l --time-style=full-iso foo
    -rw-r--r-- 1 urs urs 0 2012-12-03 18:21:09.973761852 +0000 foo
    $ TZ=America/New_York ls -l --time-style=full-iso foo
    -rw-r--r-- 1 urs urs 0 2012-12-03 13:21:09.973761852 -0500 foo
    $ TZ=Australia/Sydney find foo -printf "%TF %TT %Tz %p\n"
    2012-12-04 05:21:09.9737618520 +1100 foo
    $ tar cf bar.tar foo
    $ tar tvf bar.tar
    -rw-r--r-- urs/urs           0 2012-12-03 19:21 foo
    $ TZ=Asia/Shanghai tar tvf bar.tar
    -rw-r--r-- urs/urs           0 2012-12-04 02:21 foo
    $ # Look at the time displayed in the emacs mode line
    $ TZ=Asia/Tokyo emacs --eval "(display-time)"
    $ TZ=UTC xclock

And of course, you don't need to specify the timezone to use in every
command, but simply set the TZ environment variable for all subsequent
commands (e.g. in your ~/.profile):

    $ export TZ=Europe/Berlin

Or set the default timezone for the system using dpkg or zic -l so
that you don't need to set the TZ environment variable.

[1] To be more precise: The environment variable is not set for each
    user, you can even give a different value to each process.  That
    means you can have several terminal windows and/or X11 clocks
    and/or whatever-you-like show different times:

    $ TZ=Asia/Tokyo xterm &
    $ TZ=Asia/Tokyo xclock -title Tokyo &
    $ TZ=Europe/Berlin xterm &
    $ TZ=Europe/Berlin xclock -title Berlin &
    $ TZ=US/Pacific xclock -title "San Francisco" &

Hint: Have a look at /usr/share/zoneinfo to get an idea which timezone
descriptions are available.  To see what a timezone description
contains run from your command-line shell

    $ zdump -v America/New_York

German readers might want to read

    http://www.ibr.cs.tu-bs.de/users/thuerman/time

where I give some more background info on time.  It's > 10 years old,
some links are out-of-date and it's still not complete :-)


urs


Reply to: