Permalink
Browse files

Adding Time and DateTime #compare_with_coercion, which layers behavio…

…r on #<=> so that any combination of Time, DateTime and ActiveSupport::TimeWithZone instances can be chronologically compared

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8711 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
gbuesing committed Jan 23, 2008
1 parent 213fac6 commit ac03ad1f78d88f40924225089a4b4bfebc8c74d8
View
@@ -1,5 +1,7 @@
*SVN*
+* Adding Time and DateTime #compare_with_coercion, which layers behavior on #<=> so that any combination of Time, DateTime and ActiveSupport::TimeWithZone instances can be chronologically compared [Geoff Buesing]
+
* TimeZone#now returns an ActiveSupport::TimeWithZone [Geoff Buesing]
* Time #in_current_time_zone and #change_time_zone_to_current return self when Time.zone is nil [Geoff Buesing]
@@ -7,6 +7,11 @@ module DateTime #:nodoc:
module Calculations
def self.included(base) #:nodoc:
base.extend ClassMethods
+
+ base.class_eval do
+ alias_method :compare_without_coercion, :<=>
+ alias_method :<=>, :compare_with_coercion
+ end
end
module ClassMethods
@@ -91,6 +96,13 @@ def utc?
def utc_offset
(offset * 86400).to_i
end
+
+ # Layers additional behavior on DateTime#<=> so that Time and ActiveSupport::TimeWithZone instances can be compared with a DateTime
+ def compare_with_coercion(other)
+ other = other.comparable_time if other.respond_to?(:comparable_time)
+ other = other.to_datetime unless other.acts_like?(:date)
+ compare_without_coercion(other)
+ end
end
end
end
@@ -9,8 +9,12 @@ def self.included(base) #:nodoc:
base.class_eval do
alias_method :plus_without_duration, :+
alias_method :+, :plus_with_duration
+
alias_method :minus_without_duration, :-
alias_method :-, :minus_with_duration
+
+ alias_method :compare_without_coercion, :<=>
+ alias_method :<=>, :compare_with_coercion
end
end
@@ -218,6 +222,19 @@ def minus_with_duration(other) #:nodoc:
minus_without_duration(other)
end
end
+
+ # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
+ # can be chronologically compared with a Time
+ def compare_with_coercion(other)
+ # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do <=> comparision
+ other = other.comparable_time if other.respond_to?(:comparable_time)
+ if other.acts_like?(:date)
+ # other is a Date/DateTime, so coerce self #to_datetime and hand off to DateTime#<=>
+ to_datetime.compare_without_coercion(other)
+ else
+ compare_without_coercion(other)
+ end
+ end
end
end
end
@@ -105,7 +105,6 @@ def strftime(format)
# Use the time in UTC for comparisons
def <=>(other)
- other = other.comparable_time if other.respond_to?(:comparable_time) # to coerce time from TimeWithZone
utc <=> other
end
@@ -253,6 +253,24 @@ def test_formatted_offset_with_local
assert_equal '-05:00', dt.formatted_offset
assert_equal '-0500', dt.formatted_offset(false)
end
+
+ def test_compare_with_time
+ assert_equal 1, DateTime.civil(2000) <=> Time.utc(1999, 12, 31, 23, 59, 59)
+ assert_equal 0, DateTime.civil(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0)
+ assert_equal(-1, DateTime.civil(2000) <=> Time.utc(2000, 1, 1, 0, 0, 1))
+ end
+
+ def test_compare_with_datetime
+ assert_equal 1, DateTime.civil(2000) <=> DateTime.civil(1999, 12, 31, 23, 59, 59)
+ assert_equal 0, DateTime.civil(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 0)
+ assert_equal(-1, DateTime.civil(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 1))
+ end
+
+ def test_compare_with_time_with_zone
+ assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59) )
+ assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0) )
+ assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1) ))
+ end
protected
def with_timezone(new_tz = 'US/Eastern')
@@ -424,6 +424,24 @@ def test_formatted_offset_with_local
assert_equal '-0400', Time.local(2000, 7).formatted_offset(false)
end
end
+
+ def test_compare_with_time
+ assert_equal 1, Time.utc(2000) <=> Time.utc(1999, 12, 31, 23, 59, 59, 999)
+ assert_equal 0, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0)
+ assert_equal(-1, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0, 001))
+ end
+
+ def test_compare_with_datetime
+ assert_equal 1, Time.utc(2000) <=> DateTime.civil(1999, 12, 31, 23, 59, 59)
+ assert_equal 0, Time.utc(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 0)
+ assert_equal(-1, Time.utc(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 1))
+ end
+
+ def test_compare_with_time_with_zone
+ assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59) )
+ assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0) )
+ assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1) ))
+ end
protected
def with_timezone(new_tz = 'US/Eastern')
@@ -87,12 +87,24 @@ def test_to_s_db
def test_xmlschema
assert_equal "1999-12-31T19:00:00-05:00", @twz.xmlschema
end
-
- def test_compare
+
+ def test_compare_with_time
assert_equal 1, @twz <=> Time.utc(1999, 12, 31, 23, 59, 59)
- assert_equal 0, @twz <=> Time.utc(2000)
+ assert_equal 0, @twz <=> Time.utc(2000, 1, 1, 0, 0, 0)
assert_equal(-1, @twz <=> Time.utc(2000, 1, 1, 0, 0, 1))
end
+
+ def test_compare_with_datetime
+ assert_equal 1, @twz <=> DateTime.civil(1999, 12, 31, 23, 59, 59)
+ assert_equal 0, @twz <=> DateTime.civil(2000, 1, 1, 0, 0, 0)
+ assert_equal(-1, @twz <=> DateTime.civil(2000, 1, 1, 0, 0, 1))
+ end
+
+ def test_compare_with_time_with_zone
+ assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59) )
+ assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0) )
+ assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1) ))
+ end
def test_plus
assert_equal Time.utc(1999, 12, 31, 19, 0 ,5), (@twz + 5).time

0 comments on commit ac03ad1

Please sign in to comment.