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);


Reply via email to