ActiveRecord 4.2到5.0.1日期时间精度行为更改

时间:2016-12-26 03:38:34

标签: mysql ruby activerecord

我正在尝试使用Mysql 5.6.33和ActiveRecord 5.0.1将项目升级到mysql2 gem 0.4.5。我有许多规范测试涉及创建记录,然后搜索created_at值为<= Time.now的记录。我通过以下从ActiveRecord 4.2到ActiveRecord 5.0.1的行为更改示例总结了失败:

ActiveRecord 4

irb(main):021:0> puts Time.at(1482722443.8581448)
2016-12-26 03:20:43 +0000
=> nil
irb(main):022:0> p.updated_at = Time.at(1482722443.8581448)
=> 2016-12-26 03:20:43 +0000
irb(main):023:0> p.save
=> true
irb(main):024:0> p.updated_at
=> 2016-12-26 03:20:43 UTC
irb(main):025:0> p.reload
=> #<Profile id: 1, ...
irb(main):026:0> p.updated_at
=> 2016-12-26 03:20:43 UTC

ActiveRecord 5.0.1

> puts Time.at(1482722443.8581448)
2016-12-26 03:20:43 +0000
=> nil
> p.updated_at = Time.at(1482722443.8581448)
=> 2016-12-26 03:20:43 +0000
> p.save
=> true
> p.updated_at
=> 2016-12-26 03:20:43 UTC
> p.reload
=> #<Profile:0x0055e04486dc40
 id: 1,
 ...
> p.updated_at
=> 2016-12-26 03:20:44 UTC

正如您所看到的,在AR4的第一个示例中,数据库返回的日期时间为43秒,因此它在{{1}提供的时间戳上执行floor操作}。

在AR5中,它正在进行1482722443.8581448操作,并将round时间移动到下一整秒,从而使其从第二个43到第二个44.

这导致“将来”创建记录,我创建的示例,然后搜索created_atcreated_at的记录没有返回任何记录,因为它实际上是在未来以毫秒为单位。

这种行为是预期的,还是这个错误?我可以在AR5中配置这种毫秒舍入行为吗?

更新

如果我这样做,它看起来像在mysql中:

<= Time.now

然后:

update alerts set created_at = '2016-12-26 04:08:19.7777' limit 1;

我得到了

select created_at from alerts;

因此,mysql正在进行“四舍五入”。是否有可能从4.2到5.0.1,ActiveRecord开始用日期时间编写查询

2016-12-26 04:08:20

而不是

2016-12-26 04:08:19.7777

使用Mysql 5.6.33?

1 个答案:

答案 0 :(得分:0)

是的,ActiveRecord 5已根据this blog post更改了其行为。

以下是在ActiveRecord 5.0.1中添加此支持的two commits

要恢复旧行为,我必须添加以下monkeypatch:

module ActiveRecord
  module ConnectionAdapters
    class AbstractMysqlAdapter < AbstractAdapter
    end
    class Mysql2Adapter < AbstractMysqlAdapter
      def supports_datetime_with_precision?
        false
      end
    end
  end
end