在同时具有时间范围(Postgres类型tsrange
)和日期范围(Postgres类型daterange
)字段的表上...
保存并从数据库中检索无限制/无限时间范围会导致错误:
object.a_time_range = Time.now.utc..DateTime::Infinity.new
object.save!
object.reload
=> ArgumentError:范围值错误
但是,对日期范围执行相同操作会很好:
object.a_date_range = Date.today..Date::Infinity.new
object.save!
object.reload
有没有办法在Rails中使用无限的时间范围?
红宝石:2.3.0, 导轨:4.2.6
(另请参见ruby - Is there a way to express 'infinite time' - Stack Overflow)
答案 0 :(得分:3)
您不能将Infinity作为时间范围的一部分存储在Rails中。我相信这是因为将Infinity从字符串PSQL oid中拉出时将作为字符串值插入并解释为浮点数。因此,Date-> Float中的任何日期范围都不可行。但是您可以设法用伪(从现在开始算起一百万年)日期创建自己的范围,或者您可以只使用两个单独的日期字段并在模型中适当地解释它们。开始日期,结束日期。
在Rails 4.2+中,您可以在日期时间类型内存储一个Float :: INFINITY值。例子。
User.first.update(begin_date: DateTime.now, end_date: 'infinity')
User.first.end_date # => Infinity
但是,end_date
将不是有效日期。您只是将 string 存储在数据库中,并且在调用它时会提取 float 。
以下是处理该问题的实际代码(Rails 4.2):
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
同样,您将不能使用浮点数进行日期时间比较。但是,对于这两个值-::Float::INFINITY
和::Float::INFINITY