Why does localtime() call tzset() but localtime_r() not?

Jonathan Leffler jonathan.leffler at gmail.com
Fri Jan 11 06:44:10 UTC 2008

On Jan 10, 2008 10:00 PM, Russ Allbery <rra at stanford.edu> wrote:

> "Jonathan Leffler" <jonathan.leffler at gmail.com> writes:
> > Actually, the subject pretty much says it all.
> > In tzcode2007k (also in 2007h), the code in localtime.c is:
> >
> >[...]
> >
> > I can't immediately see a justification for the asymmetry in the POSIX
> > specification of these functions, but I could be missing something.
> My guess is it's because tzset() sets global variables and hence isn't
> threadsafe.

I wondered about that...The POSIX specification says:

Unlike *localtime*(), the reentrant version is not required to set *tzname*.
[image: [Option End]]

[TSF <javascript:open_code('TSF')>] [image: [Option Start]] If the reentrant
version does not set *tzname*, it shall not set *daylight* and shall not set
*timezone*. [image: [Option End]]
I interpret that as meaning "it might not call tzset() - but if it does call
tzset(), tzset() shall do the whole job, not just part of the job".

However, consider the following simple test program ("Black JL:" is my Unix
prompt on machine 'black'):

Black JL: cat chk-localtime_r.c
#include <time.h>
#include <stdio.h>

int main(void)
    struct tm tp;
    time_t now = time(0);
    struct tm *tx = localtime_r(&now, &tp);
    char buffer[30];
    if (tx != 0)
        char *s = asctime_r(&tp, buffer);
        printf("%ld = %s", (long)now, s);
chk-localtime_r.c libtz.a
Black JL: date; ./chk; ./chk.sys
Thu Jan 10 22:35:52 PST 2008
1200033352 = Fri Jan 11 06:35:52 2008
1200033352 = Thu Jan 10 22:35:52 2008
Black JL:

Using the Olson code  (tzcode2007k), the program defaults to UTC (GMT)
because tzset() was never called explicitly.  Using the System code (Solaris
10), the same program defaults to my local time zone (US/Pacific).  So, at
least there is a difference between the behaviour of the Solaris library and
the Olson library in this respect.

I guess the POSIX manual allows this - and the Olson implementation may well
choose to implement localtime_r() without tzset() because tzset() is not
re-entrant or thread-safe.

The POSIX standard says of localtime(), that:

CX <javascript:open_code('CX')>] [image: [Option Start]] The *localtime*()
function need not be reentrant. A function that is not required to be
reentrant is not required to be thread-safe.

The same words are not said of tzset() -- which might conceivably be an
omission, or it might imply that the function is supposed to be thread-safe
and reentrant.

Jonathan Leffler <jonathan.leffler at gmail.com>  #include <disclaimer.h>
Guardian of DBD::Informix - v2007.0914 - http://dbi.perl.org
"Blessed are we who can laugh at ourselves, for we shall never cease to be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mm.icann.org/pipermail/tz/attachments/20080110/1dea4d51/attachment.htm>

More information about the tz mailing list