Yesterday I ran into a situation where my TZ environment variable became unset, resulting in the creation of a 'local' timezone falling through to C<_from_etc_timezone()>.
I don't have '/etc/timezone' but do have '/etc/TIMEZONE'. C<_from_etc_timezone()> assumes these files are of the same format, but I found that not to be true.
From 'man TIMEZONE':
DESCRIPTION
This file sets the time zone environment variable TZ, and
the locale-related environment variables LANG, LC_COLLATE,
LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC, and LC_TIME./etc/TIMEZONE is a symbolic link to /etc/default/init.
The number of environments that can be set from
/etc/default/init is limited to 20.From 'man init':
/etc/default/init File
Default values can be set for the following flags in
/etc/default/init. For example: TZ=US/Pacific TZ Either specifies the timezone information (see
ctime(3C)) or the name of a timezone information file
/usr/share/lib/zoneinfo.My '/etc/default/init' looks like:
# @(#)init.dfl 1.5 99/05/26 # # This file is /etc/default/init. /etc/TIMEZONE is a symlink to this # file. This file looks like a shell script, but it is not. To maintain # compatibility with old versions of /etc/TIMEZONE, some shell # constructs (i.e., export commands) are allowed in this file, but are # ignored. # # Lines of this file should be of the form VAR=value, where VAR is one # of TZ, LANG, CMASK, or any of the LC_* environment variables. # TZ=US/Eastern CMASK=022 LC_COLLATE=en_US.ISO8859-1 LC_CTYPE=en_US.ISO8859-1 LC_MESSAGES=C LC_MONETARY=en_US.ISO8859-1 LC_NUMERIC=en_US.ISO8859-1 LC_TIME=en_US.ISO8859-1
I don't know if this differs from platform to platform, but here's my info:
SunOS - 5.8 Generic_108528-21 sun4u sparc SUNW,Sun-Fire-880 Solaris
Attached are patches to 'DateTime/TimeZone/Local.pm' and '04local.t' that correct this for me.
Thanks,
- Dan Boorstein
--- ./04local.t 2004-04-22 08:14:12.231985000 -0400
+++ t/04local.t 2004-04-21 17:43:57.000000000 -0400
@@ -18,6 +18,7 @@
# make sure it doesn't find an /etc/localtime file
$^W = 0;
local *DateTime::TimeZone::Local::_from_etc_timezone = sub { undef };
+ local *DateTime::TimeZone::Local::_from_etc_TIMEZONE = sub { undef };
local *DateTime::TimeZone::Local::_from_etc_localtime = sub { undef };
local *DateTime::TimeZone::Local::_read_etc_sysconfig_clock = sub { undef };
$^W = 1;
--- ./Local.pm 2004-04-22 08:14:00.748984000 -0400
+++ lib/DateTime/TimeZone/Local.pm 2004-04-22 08:05:57.614984000 -0400
@@ -11,6 +11,7 @@
foreach ( qw( env
etc_localtime
etc_timezone
+ etc_TIMEZONE
etc_sysconfig_clock
) )
{
@@ -78,16 +79,9 @@
sub _from_etc_timezone
{
- my $tz_file;
- foreach ( qw( /etc/timezone /etc/TIMEZONE ) )
- {
- if ( -f && -r _ )
- {
- $tz_file = $_;
- last
- }
- }
- return unless $tz_file;
+ my $tz_file = '/etc/timezone';
+
+ return unless -f $tz_file && -r _;
local *TZ;
open TZ, "<$tz_file"
@@ -100,6 +94,31 @@
return eval { DateTime::TimeZone->new( name => $name ) };
}
+sub _from_etc_TIMEZONE
+{
+ my $tz_file = '/etc/TIMEZONE';
+
+ return unless -f $tz_file && -r _;
+
+ local *TZ;
+ open TZ, "<$tz_file"
+ or die "Cannot read $tz_file: $!";
+
+ my $name;
+ while ($name = <TZ>)
+ {
+ if ($name =~ /\A\s*TZ=\s*(\S+)/)
+ {
+ $name = $1;
+ last;
+ }
+ }
+
+ close TZ;
+
+ return $name && eval { DateTime::TimeZone->new( name => $name ) };
+}
+
# for systems where /etc/localtime is a copy of a zoneinfo file
sub _find_matching_zoneinfo_file
{
