Question: what should the result of this comparison be?
my $dt1 = DateTime->new( year => 2003, month => 3, day => 23, hour => 12,
time_zone => 'America/Chicago' );
my $dt2 = DateTime->new( year => 2003, month => 3, day => 23, hour => 12,
time_zone => 'floating');
print '$dt1 <=> $dt2: ', $dt1 <=> $dt2, "\n";
I think these two datetimes should be equal: a floating time should be
converted to the time zone of the other object, before it is compared.
(I need this for DateTime::Calendar::Christian. I do a comparison
$datetime >= $reform_date to see if a date is a Gregorian date. As the
situation is now, Chicago switches to the new calendar on 1752-09-02,
at 18:09:24. This is very inconvenient for Chicagoans.)
Again, I've included a patch below. Please take a look to see if you
like it.
Eugene
diff -ur DateTime-0.08/lib/DateTime.pm DateTime-new/lib/DateTime.pm
--- DateTime-0.08/lib/DateTime.pm Sun Mar 23 22:08:28 2003
+++ DateTime-new/lib/DateTime.pm Sun Mar 23 23:32:06 2003
@@ -26,7 +26,7 @@
#
use overload ( 'fallback' => 1,
'<=>' => '_compare_overload',
- 'cmp' => '_compare_overload',
+ 'cmp' => '_compare_overload_cmp',
'-' => '_subtract_overload',
'+' => '_add_overload',
);
@@ -712,9 +712,14 @@
return $_[2] ? - $_[0]->compare( $_[1] ) : $_[0]->compare( $_[1] );
}
+sub _compare_overload_cmp
+{
+ return $_[2] ? - $_[0]->compare( $_[1], 1 ) : $_[0]->compare( $_[1], 1 );
+}
+
sub compare
{
- my ( $class, $dt1, $dt2 ) = ref $_[0] ? ( undef, @_ ) : @_;
+ my ( $class, $dt1, $dt2, $consistent ) = ref $_[0] ? ( undef, @_ ) : @_;
return undef unless defined $dt2;
@@ -725,6 +730,21 @@
unless ( UNIVERSAL::can( $dt1, 'utc_rd_values' ) &&
UNIVERSAL::can( $dt2, 'utc_rd_values' ) );
+ if ( ! $consistent &&
+ UNIVERSAL::can( $dt1, 'time_zone' ) &&
+ UNIVERSAL::can( $dt2, 'time_zone' ) )
+ {
+ my $is_floating1 = $dt1->time_zone->is_floating;
+ my $is_floating2 = $dt2->time_zone->is_floating;
+ if ( $is_floating1 && ! $is_floating2 )
+ {
+ $dt1 = $dt1->clone->set_time_zone( $dt2->time_zone );
+ }
+ elsif ( $is_floating2 && ! $is_floating1 )
+ {
+ $dt2 = $dt2->clone->set_time_zone( $dt1->time_zone );
+ }
+ }
my ($days1, $secs1) = $dt1->utc_rd_values;
my ($days2, $secs2) = $dt2->utc_rd_values;
@@ -1363,16 +1383,31 @@
$cmp = DateTime->compare($dt1, $dt2);
- @dates = sort { DateTime->compare($a, $b) } @dates;
-
Compare two DateTime objects. The semantics are compatible with
Perl's C<sort()> function; it returns -1 if $a < $b, 0 if $a == $b, 1
if $a > $b.
+If one of the two DateTime objects has a floating time zone, it will
+first be converted to the time zone of the other object. This is what
+you want most of the time, but it can lead to inconsistent results
+when you compare a number of DateTime objects with different time zones.
+If you want to have consistent results (because you want to sort a
+number of objects, for example), you can pass an additional boolean
+parameter:
+
+ @dates = sort { DateTime->compare($a, $b, 1) } @dates;
+
+In this case, objects with a floating time zone will be sorted as if
+they were UTC times.
+
Of course, since DateTime objects overload comparison operators, you
can just do this anyway:
@dates = sort @dates;
+
+The numeric comparison operators <, > and == implement the usual
+behavior; the stringwise comparison operators C<cmp>, C<lt> and
+C<gt> implement the consistent comparisons.
=back
diff -ur DateTime-0.08/t/07compare.t DateTime-new/t/07compare.t
--- DateTime-0.08/t/07compare.t Wed Mar 12 08:43:25 2003
+++ DateTime-new/t/07compare.t Sun Mar 23 23:01:13 2003
@@ -1,6 +1,6 @@
use strict;
-use Test::More tests => 17;
+use Test::More tests => 19;
use DateTime;
@@ -91,3 +91,14 @@
ok( ($infinity <=> $date1) == 1, 'Comparison overload $inf <=> $a');
+# comparison with floating time
+
+$date1 = DateTime->new( year => 1997, month => 10, day => 24,
+ hour => 12, minute => 0, second => 0,
+ time_zone => 'America/Chicago' );
+$date2 = DateTime->new( year => 1997, month => 10, day => 24,
+ hour => 12, minute => 0, second => 0,
+ time_zone => 'floating' );
+
+ok( ($date1 <=> $date2) == 0, 'Comparison with floating time (<=>)' );
+ok( ($date1 cmp $date2) == 1, 'Comparison with floating time (cmp)' );