Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does a Perl script need to call `tzset` before calling `localtime`?

I recently learned how to change the timezone returned by localtime in Perl.

use POSIX qw(tzset);
print localtime . "\n";
$ENV{TZ} = 'America/Los_Angeles';
print localtime . "\n";
tzset;
print localtime . "\n";

Outputs

Wed Apr 15 15:58:10 2009
Wed Apr 15 15:58:10 2009
Wed Apr 15 12:58:10 2009

Notice how the hour only changes after calling tzset.

This is perl, v5.8.8 built for x86_64-linux-thread-multi

However, on my systems I'm getting,

Fri Jul 8 19:00:51 2016
Fri Jul 8 16:00:51 2016
Fri Jul 8 16:00:51 2016

Notice how on my system, the hour changes without calling tzset. This holds true on recent versions of Perl in Ubuntu and Illumos, as well as Perl v5.8.8 on Solaris 10.

So if all my tests indicate that tzset has no effect, why / what other systems require tzset to be called explicitly? Do I still need to call tzset to remain compatible with certain environments, or is it now a thing of the past?

like image 829
700 Software Avatar asked Jul 08 '16 23:07

700 Software


1 Answers

TL;DR: Starting with Perl v5.8.9 (released in 2011) calling tzset when changing $ENV{TZ} isn't needed anymore.


Perl's localtime calls localtime_r(3) internally, which isn't required to call tzset(3). The Linux manpage advises:

According to POSIX.1-2004, localtime() is required to behave as though tzset(3) was called, while localtime_r() does not have this requirement. For portable code tzset(3) should be called before localtime_r().

In older non-multithreaded Perls, or if localtime_r(3) wasn't available during build, localtime(3) is used instead. In that case, a call to tzset would have been unnecessary, per POSIX:

Local timezone information is used as though localtime() calls tzset()

although there seem to have been times where glibc didn't adhere to that:

As for any code which doesn't call tzset all the time: this definitly won't change. It's far too expensive. And for what? The 0.000001% of the people who take the laptops on a world tour and expect, e.g., syslog messages with dates according to the native timezone. This is not justification enough. Just restart your machine.

This did change though and glibc now does act as if tztime(3) was called, but only for non-reentrant localtime which might not be what your Perl was compiled to use.

There have been two Perl bug reports regarding this: #26136 and #41591.

As a fix, Perl now decides at configuration time whether an implicit tzset(3) needs to be done, which makes specifying it in user code superfluous.

like image 141
a3f Avatar answered Sep 29 '22 10:09

a3f