为什么时间数学计算 return IRB 中的一个值但将差异值发送到 SQL?

Why does a Time math calculation return one value in IRB but sends a diff value to SQL?

我的 Post 模型中有一个方法如下所示:

  def self.num_posted_x_days_ago(n)
    start_date = Time.now.midnight - n.day
    end_date = Time.now.midnight - (n+1).day
    where(created_at: start_date..end_date).count
  end

当我在 IRB 中 运行 时,我得到这个:

> Post.num_posted_x_days_ago(8)
   (0.3ms)  SELECT COUNT(*) FROM "posts"  WHERE ("posts"."created_at" BETWEEN '2015-02-27 05:00:00.000000' AND '2015-02-26 05:00:00.000000')
=> 0

请注意,对于 start_dateend_date,日期的 Time 都是 05:00:00.000000

但是当我将 binding.pry 添加到方法中并检查 start_dateend_date 时,我得到了这个:

1] pry(Post)> start_date
=> 2015-02-26 00:00:00 -0500
[2] pry(Post)> end_date
=> 2015-02-25 00:00:00 -0500

显示从午夜开始的正确时间。

当我尝试在控制台手动完成所有操作时,我得到以下信息:

[31] pry(main)> Time.now.midnight
=> 2015-03-07 00:00:00 -0500
[32] pry(main)> Time.now.midnight - 9.days
=> 2015-02-26 00:00:00 -0500
[33] pry(main)> Time.now.midnight - 9.day
=> 2015-02-26 00:00:00 -0500

注意所有时间都显示午夜。

是什么导致了这种不匹配?

数据库以 UTC 格式存储时间。当您在控制台中显示它时,它会显示您当地的时区。

假设您对在您所在时区的特定日期写的帖子感兴趣,结果应该是您所期望的。如果您想在 UTC 时区检索一天的帖子,请将 Time.now.midnight 替换为 Time.now.utc.midnight

---编辑---

数据库中存储的所有日期均使用 UTC。每当 Rails 保存到数据库或从数据库中检索时,它都会从您的本地时区转换为 UTC,反之亦然。这就是为什么您在 SQL 查询中看到不同时间的原因。如果您检查返回的对象,您会发现实际上这些都是正确的结果。

唯一要记住的是,如果您 运行 应用程序在不同的服务器上,系统时区可能会有所不同(最好将服务器时区设置为 UTC),所以Time.now.midnight 的含义与在您的本地计算机上有所不同。

如果您想确保 Rails 始终从美国东部时间午夜检索帖子,您需要明确指定时区:

Time.now.in_time_zone('EST').midnight

或(观察夏令时应切换到美国东部时间):

Time.now.in_time_zone('America/New_York').midnight