The following change from DateTime 1.28 to 1.29 breaks my code:
CVS diff of file DateTime.pm from 1.298 to 1.299
http://cvs.sourceforge.net/viewcvs.py/perl-date-time/modules/DateTime.pm/lib/DateTime.pm?r1=1.298&r2=1.299
In my program, I need to know the difference between two dates in
time-of-day-independent days/months, but also do DST-dependent
calculations. However, after this change, subtracting DST DateTime
objects whose difference crosses the spring DST change causes a day to
be dropped from the resulting Duration object. The number of days
between two dates (at midnight) should be independent of whether the
calculation is being done on DST dates. The documentation for DateTime
notes that there is no constant conversion between hours and days, I
would assume for this very reason.
The motivation for this change seems to be to have subtract_datetime
return a Duration that is the difference of the UTC equivalents of the
given (possibly local) DateTime objects. While I can see the utility of
wanting to know the UTC time difference, this method is documented as
not returning any sort of absolute time difference. The resulting
Duration object is only useful in relation to the DateTime objects that
created it. Therefore, it would seem reasonable that the duration would
be defined in terms of the timezone that created it.
I am further confused by this change because it does not update the
behavior of associated methods such as add_duration. In fact, adding
the result of subtract_datetime to the subtrahend using add_duration
returns a value that is different from the original minuend of
subtract_datetime. Whatever the intended behavior of these methods, it
is not consistent.
It would seem to me that if this really is the desired behavior of
subtract_datetime, there should be two sets of methods, one for doing
calculations relative to the current timezone and one that always
produces durations relative to UTC equivalents (using the suffixes
*_utc or *_local to distinguish them).
Applying the inverse diff of this change causes my program to appear to
work normally again.
The attached script demonstrates the described behavior.
- Alex Docauer <[EMAIL PROTECTED]>
#!/usr/bin/perl -w
require DateTime;
use Data::Dumper;
# Show the time difference between the two dates.
sub compare {
my($begin, $end) = @_;
$diff = $end->clone()->subtract_datetime($begin);
print("Begin: $begin End: $end " .
"Delta-Months: " . $diff->in_units('months') . "\n" .
Dumper($diff->deltas()));
}
# We should be able to use the difference to get back to where we started
sub orthogonal {
my($begin, $end) = @_;
$diff = $end->clone()->subtract_datetime($begin);
$new_begin = $end->clone()->subtract_duration($diff);
$new_end = $end->clone()->add_duration($diff);
print("New-Begin: $new_begin New-End: $new_end\n" );
}
sub case {
print "\n$_[0] ***********************************\n";
}
case("Case 1: Floating");
$float_begin = new DateTime(year => 2005, month => 3);
$float_end = new DateTime(year => 2005, month => 6);
compare($float_begin, $float_end);
orthogonal($float_begin, $float_end);
case("Case 2: GMT");
$gmt_begin = new DateTime(year => 2005, month => 3,
time_zone => "GMT");
$gmt_end = new DateTime(year => 2005, month => 6,
time_zone => "GMT");
compare($gmt_begin, $gmt_end);
orthogonal($gmt_begin, $gmt_end);
case("Case 3: Central DST: Spring forward");
$local_begin = new DateTime(year => 2005, month => 3,
time_zone => "America/Chicago");
$local_end = new DateTime(year => 2005, month => 6,
time_zone => "America/Chicago");
compare($local_begin, $local_end);
orthogonal($local_begin, $local_end);
case("Case 4: Central DST: Fall back");
$alt_begin = new DateTime(year => 2005, month => 9,
time_zone => "America/Chicago");
$alt_end = new DateTime(year => 2005, month => 12,
time_zone => "America/Chicago");
compare($alt_begin, $alt_end);
orthogonal($alt_begin, $alt_end);