You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Kirk Noda <ki...@nmseg.com> on 2007/12/28 22:15:54 UTC

mod_perl, ENV{'TZ'}, and localtime

Hello,

I'd like to reference the Tues 03 Oct '06 thread with subject:

RE: Using ENV{'TZ'} in mod_perl

http://mail-archives.apache.org/mod_mbox/perl-modperl/200610.mbox/browser

The thread seemed to die off.  Still, is there a way to use $ENV{TZ} 
to modify the behavior of localtime?  I get the same result on 
mod_perl 1.99_16 and 2.0.3.  PerlTaintCheck is off for 
both.  POSIX::tzset() does not correct the mis(?)behavior.  I'd like 
to get this to work with the apache 2.0.52 + mod_perl 1.99_16 setup.

BTW, This did work way back on apache 1.3.27 + mod_perl 1.27.



###
### Test script
###

#!/usr/bin/perl 

use strict;
use warnings;
use POSIX qw(tzset tzname);

print "Content-type: text/plain\n\n";

$ENV{'TZ'} = 'US/Eastern';
POSIX::tzset();
my $eastern = localtime();
my ($estd, $edst) = POSIX::tzname();

foreach my $tmp (sort keys %ENV) {
   printf("%-30s:%s\n",$tmp,$ENV{$tmp});
}

print "\n";

$ENV{'TZ'} = 'US/Pacific';
POSIX::tzset();
my $pacific = localtime();
my ($pstd, $pdst) = POSIX::tzname();

print
"Eastern: $eastern\n",
"Eastern: std: $estd dst: $edst\n",
"Pacific: $pacific\n",
"Pacific: std: $pstd dst: $pdst\n",
;

###
### Test 1 (fails)
###
GATEWAY_INTERFACE             :CGI/1.1
MOD_PERL                      :mod_perl/2.0.3
MOD_PERL_API_VERSION          :2
SERVER_SOFTWARE               :Apache/2.2.6 (Fedora)

Eastern: Fri Dec 28 11:59:31 2007
Eastern: std: PST dst: PDT
Pacific: Fri Dec 28 11:59:31 2007
Pacific: std: PST dst: PDT

###
### Test 2 (fails)
###
GATEWAY_INTERFACE             :CGI/1.1
MOD_PERL                      :mod_perl/1.99_16
SERVER_SOFTWARE               :Apache/2.0.52 (Red Hat)

Eastern: Fri Dec 28 12:04:04 2007
Eastern: std: PST dst: PDT
Pacific: Fri Dec 28 12:04:04 2007
Pacific: std: PST dst: PDT

###
### Test 3 (works, non mod_perl)
###
GATEWAY_INTERFACE             :CGI/1.1
SERVER_SOFTWARE               :Apache/2.2.6 (Fedora)

Eastern: Fri Dec 28 15:26:35 2007
Eastern: std: EST dst: EDT
Pacific: Fri Dec 28 12:26:35 2007
Pacific: std: PST dst: PDT

###
### Test 4 (works, really old mod_perl+apache)
###
GATEWAY_INTERFACE             :CGI-Perl/1.1
MOD_PERL                      :mod_perl/1.27
SERVER_SOFTWARE               :Apache/1.3.27 (Unix) mod_perl/1.27 
AuthMySQL/2.20 PHP/4.2.3 mod_ssl/2.8.11 OpenSSL/0.9.6g

Eastern: Fri Dec 28 15:44:11 2007
Eastern: std: EST dst: EDT
Pacific: Fri Dec 28 12:44:12 2007
Pacific: std: PST dst: PDT


Re: mod_perl, ENV{'TZ'}, and localtime

Posted by Kirk Noda <ki...@nmseg.com>.
At 09:12 PM 12/28/2007, you wrote:
[...]
>The reason this does not work under modperl version 2.0 is because under
>handler "perl-script", %ENV is untied from the C environment.  The
[...]

Thanks very much, that works.


Re: mod_perl, ENV{'TZ'}, and localtime

Posted by Michael Schout <ms...@gkg.net>.
Kirk Noda wrote:
> The thread seemed to die off.  Still, is there a way to use $ENV{TZ} to
> modify the behavior of localtime?

The reason this does not work under modperl version 2.0 is because under
handler "perl-script", %ENV is untied from the C environment.  The
localtime() function is implemented in C, and as a result, it will never
see the changes you made to $ENV{TZ} from mod_perl.

The way I got around this was to use Env::C, and override
CORE::localtime() with something like:

package MyLocaltime;

use Env::C;

sub import {
    my $class = shift;
    $class->export('CORE::GLOBAL', 'localtime');
}

sub localtime {
    my $time = shift;
    $time = time unless defined $time;

    my $orig_tz = Env::C::getenv('TZ');
    Env::C::setenv('TZ', $ENV{TZ}, 1);

    my @ret = CORE::localtime($time);

    Env::C::setenv('TZ', $orig_tz, 1);

    return @ret;
}

The real problem is that this is only safe under a prefork MPM because
it is not thread safe.  There really ought to be an option (IMO) where
you can make the untie of %ENV under perl-script to be optional.  Maybe
something like PerlOptions +NoUntieEnv or something so that if you are
running under a prefork MPM, you do not need to resort to tactics like
the above.

Regards,
Michael Schout