Rails 中无限时间范围的问题

Posted

技术标签:

【中文标题】Rails 中无限时间范围的问题【英文标题】:Problems with infinite time range in Rails 【发布时间】:2019-04-11 22:46:08 【问题描述】:

在同时具有时间范围(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)

【问题讨论】:

【参考方案1】:

您不能将 Infinity 作为时间范围的一部分存储在 Rails 中。我相信这是因为 Infinity 将作为字符串值插入,并在从本机 PSQL oid 中拉出时解释为浮点数。因此,从 Date -> Float 的任何日期范围都不可行。但是您可以设法使用伪(从现在起 100 万年)日期创建自己的范围,或者您可以只使用两个单独的日期字段并在模型中适当地解释它们。开始日期,结束日期。

在 Rails 4.2+ 中,您可以在 datetime 类型中存储一个 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 这两个值有一​​个特殊情况可能很简单

【讨论】:

感谢您将其分解。听起来我最好的选择是使用遥远的未来伪结束日期。

以上是关于Rails 中无限时间范围的问题的主要内容,如果未能解决你的问题,请参考以下文章

具有多态模型的 Rails 范围

在 rails 中显示范围的结果

Google表格中无限真实动态范围平均值的ArrayFormula

Rails 范围政策不接受其他标准

Rails 包含范围

如何在整个 Rails 活动记录关联链中取消特定模型的默认范围?