Subject: | Default time zone overriding explicit time zone (includes solution) |
The bug involves the situation in which the first argument for
parse_datetime includes an explicit time zone, and the second argument
is a default timezone.
Consider the following code. A $zone argument is sent but the date
string already has an explicit timezone.
$date = '2008-01-04T00:00:00-0800';
$zone = '-0500';
$dt = DateTime::Format::DateParse->parse_datetime($date, $zone);
In situations like that, Date::Parse returns the zone that was set in
the date/time string, not the default zone. Currently
DateTime::Format::DateParse returns the default zone.
I've attached a test script that demonstrates the situation. I've also
attached a modified DateParse.pm that fixes the problem. Look for the
string "# FIX" in the code. The fix is to simply check if $offset is
defined. If it is, the script uses
DateTime::TimeZone->offset_as_string($offset) to produce an offset
string compatible with DateTime->new.
Subject: | DateParse.pm |
package DateTime::Format::DateParse;
# Copyright (C) 2005-6 Joshua Hoblitt
#
# $Id: DateParse.pm 3517 2006-09-17 23:10:10Z jhoblitt $
use strict;
use vars qw($VERSION);
$VERSION = '0.04';
use DateTime;
use DateTime::TimeZone;
use Date::Parse qw( strptime );
use Time::Zone qw( tz_offset );
sub parse_datetime {
my ($class, $date, $zone) = @_;
# str2time() calls strptime() internally so it's more efficent to use
# strptime() directly. However, the extra validation done by using
# DateTime->new() instad of DateTime->from_epoch() may make it into a net
# loss. In the end, it turns out that strptime()'s offset information is
# needed anyways.
my @t = strptime( $date, $zone );
return undef unless @t;
my ($ss, $mm, $hh, $day, $month, $year, $offset) = @t;
my %p;
if ( $ss ) {
my $fraction = $ss - int( $ss );
$p{ nanosecond } = $fraction * 1e9 if $fraction;
$p{ second } = int $ss;
}
$p{ minute } = $mm if $mm;
$p{ hour } = $hh if $hh;
$p{ day } = $day if $day;
$p{ month } = $month + 1 if $month;
$p{ year } = $year ? $year + 1900 : DateTime->now->year;
# unless there is an explict ZONE, Date::Parse seems to parse date only
# formats, eg. "1995-01-24", as being in the 'local' timezone.
unless ( defined $zone || defined $offset ) {
return DateTime->new(
%p,
time_zone => 'local',
);
}
# FIX
if ( defined $offset ) {
return DateTime->new(
%p,
time_zone => DateTime::TimeZone->offset_as_string($offset),
);
}
if ( $zone ) {
if ( DateTime::TimeZone->is_valid_name( $zone ) ) {
return DateTime->new(
%p,
time_zone => $zone,
);
} else {
# attempt to convert Time::Zone tz's into an offset
return DateTime->new(
%p,
time_zone =>
# not an Olson timezone, no DST info
DateTime::TimeZone::offset_as_string( tz_offset( $zone ) ),
);
}
}
return DateTime->new(
%p,
time_zone =>
# not an Olson timezone, no DST info
DateTime::TimeZone::offset_as_string( $offset ),
);
}
1;
__END__
Subject: | default-timezone.4posting.pl |
#!/usr/bin/perl -w
use strict;
use DateTime::Format::DateParse;
# variables
my ($dt, $date_str, $default_tz);
$date_str = '2008-01-04T00:00:00-0800';
$default_tz = '-0500';
$dt = DateTime::Format::DateParse->parse_datetime($date_str, $default_tz);
# SHOULD return -0800, actually returns -0500
print 'parsed tz: ', $dt->strftime('%z'), "\n";