Hello,

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
 {

Reply via email to