When comparing DateTimes
, all objects being compared must be the same type. However, I have a data set that has nil
dates. I want to treat these dates as older (or perhaps newer) than any other date. Is there a way to construct a benign value that will compare as older (or alternatively, newer) than any other date?
example:
data = [
{ name: :foo, timestamp: make_benign(some_valid_timestamp) },
{ name: :bar, timestamp: make_benign(nil)}
]
data.sort_by{|datum| datum[:timestamp]} #=> [<bar>, <foo>]
data.max_by {|datum| datum[:timestamp]} #=> <foo>
data.min_by {|datum| datum[:timestamp]} #=> <bar>
EDIT: I happen to be stuck on ruby 1.9 for this problem, so solutions for older versions of ruby would be nice. (But newer solutions also are nice for future reference)
From the docs, the requirement is not that "all objects are the same type". It says:
The other should be a date object or a numeric value as an astronomical Julian day number.
So for a benign value that is guaranteed to be before/after any date, you could use -Float::INFINITY
and Float::INFINITY
accordingly.
DateTime.now > Float::INFINITY #=> false
DateTime.now > -Float::INFINITY #=> true
EDIT:
So we need a solution that works in Ruby 1.9 and Rails 3.2.9, huh...
Well the reason the above won't work is because of this monkeypatch in ActiveSupport:
class DateTime
def <=>(other)
super other.to_datetime
end
end
This is particularly problematic. Unfortunately, you may need to just use a "very big/small number" instead...
However, if you're able to upgrade a little bit to Rails 3.2.13 (or apply this updated monkeypatch manually), where the method signature was changed to:
class DateTime
def <=>(other)
super other.kind_of?(Infinity) ? other : other.to_datetime
end
end
...Then you can use Date::Infinity
(TIL that's a thing) instead of Float::Infinity
, and this "fixed" version of the method now handles it correctly:
DateTime.now > Date::Infinity.new #=> false
DateTime.now > -Date::Infinity.new #=> true