mod_perl 2 has an annoying…feature. Because the system environ struct is not thread safe, mod_perl’s perl-script handler unties the %ENV hash from the actual environment. That means, anything that uses the C getenv/setenv/unsetenv functions to read the environment will not see changes that were made to %ENV.
An obvious example is Perl’s localtime function. It actually calls the system localtime function, which uses the C getenv to check the current value of the timezone environment variable TZ. If you try to change the timezone in a mod_perl2 program by assigning to $ENV{TZ}, localtime won’t know it.
The solution is to use the Env::C module and it’s getenv/setenv/unsetenv wrappers. It works fine, but it’s a bit cumbersome. But a simple module, loaded at server-startup time, can wrap the system localtime in a function that takes care of the environment.
package Apache2::Localtime;
use Env::C;
use Exporter;
use strict;
our @ISA = qw(Exporter);
our @EXPORT = qw(localtime);
sub import {
my $class = shift;
$class->export('CORE::GLOBAL', 'localtime');
}
sub localtime {
my $time = shift || time;
return localtime($time) unless $ENV{TZ};
my $orig_tz = Env::C::getenv('TZ');
Env::C::setenv('TZ', $ENV{TZ}, 1);
my(@ret, $ret);
if(wantarray) {
@ret = CORE::localtime($time);
} else {
$ret = CORE::localtime($time);
}
if(defined $orig_tz) {
Env::C::setenv('TZ', $orig_tz, 1);
} else {
Env::C::unsetenv('TZ');
}
return wantarray ? @ret : $ret;
}
1;
Put that in your @INC path at Apache2/Localtime.pm and then add use Apache2::Localtime to a PerlRequire .../initialize.pl script or something similar. The new function should override the built-in localtime and keep your timeonzes in sync.
The code was mostly taken from here.