On a table with both time range (Postgres type tsrange
) and date range (Postgres type daterange
) fields...
Saving and then retrieving an unbound/infinite time range from DB causes an error:
object.a_time_range = Time.now.utc..DateTime::Infinity.new
object.save!
object.reload
=> ArgumentError: bad value for range
However, doing the same with date range works fine:
object.a_date_range = Date.today..Date::Infinity.new
object.save!
object.reload
Is there a way to use infinite time ranges in Rails?
ruby: 2.3.0, rails: 4.2.6
(See also ruby - Is there a way to express 'infinite time' - Stack Overflow)
You cannot store Infinity as part of a time range in Rails. I believe this is because Infinity is going to be inserted as a string value and interpreted as a float when pulled out of the native PSQL oid. So, any date range from Date -> Float will not be viable. But you can manage to create your own range with pseudo (1 million years from now) dates or you can just use two separate date fields and interpret them appropriately in the model. Begin date, end date.
In Rails 4.2+, you can store a Float::INFINITY value inside your datetime type. Example.
User.first.update(begin_date: DateTime.now, end_date: 'infinity')
User.first.end_date # => Infinity
However, end_date
will not be a valid date. You're just storing the string in the database and you're pulling out a float when your call it.
Here's the actual (Rails 4.2) code that handles that:
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class DateTime < Type::DateTime # :nodoc:
include Infinity
def type_cast_for_database(value)
if has_precision? && value.acts_like?(:time) && value.year <= 0
bce_year = format("%04d", -value.year + 1)
super.sub(/^-?\d+/, bce_year) + " BC"
else
super
end
end
def cast_value(value)
if value.is_a?(::String)
case value
when 'infinity' then ::Float::INFINITY
when '-infinity' then -::Float::INFINITY
when / BC$/
astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
else
super
end
else
value
end
end
end
end
end
end
end
Again, you will not be able to do date time comparisons with a float. But, it's probably simple enough to have a special case for these two values -::Float::INFINITY
and ::Float::INFINITY
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With