Rails不会转换时区(PostgreSQL)

6

我在使用Rails 3.0.4和PostgreSQL 9.0时遇到了与时区相关的问题。我正在使用自定义作用域,在其中添加一些条件、连接等。

问题是,Rails没有将时间转换为我的本地时区。以下是作用域的代码:

  scope :with_activities_within_range_in_week, lambda{ |latMin, lngMin, latMax, lngMax, date|
    select("date_trunc('day', activities.starting_at) as date,
      count(activities.id) as value
    ") \
    .within(latMin, lngMin, latMax, lngMax) \
    .joins(:activities) \
    .merge(Activity.in_week(date)) \
    .group("date") \
    .order("date")
  }

within方法用于检查范围,而Activity.in_week作用域返回以下内容:

where("activities.starting_at >= ? AND activities.starting_at < ?", start, stop)

在select语句中,我想将starting_at字段截断到天。对于日期字段,我得到以下输出:
2011-04-07 18:48:32
2011-04-02 14:07:20
2011-04-02 14:06:49

不幸的是它没有包含时区。当我尝试通过“正常”的Rails函数访问我的模型时,它可以工作:

puts Activity.first.starting_at
-> 2011-04-15 06:47:55 +0200

我做错了什么?希望有人可以帮忙! 谢谢, tux

activities.starting_at 在数据库中是什么类型?如果在 psql 中选择 activitiesstarting_at,会发生什么? - mu is too short
activities.starting_at 是一个 timestamp without a timezone(存储在 UTC 中)。select starting_at from activities 返回的是 2011-04-15 04:47:34,同样没有时区。但是 Rails 不应该自动将时间转换为特定的时区吗?通过我在问题中提供的示例 puts Activity.first.starting_at -> 2011-04-15 06:47:55 +0200,它可以工作。 - 23tux
我发现了另一件有趣的事情:当我尝试迭代结果并转储我的日期字段的类时,我得到了String。但它应该是ActiveSupport::TimeWithZone。我阅读了postgresql的文档,并且date_trunc('day', activities.starting_at)应该返回一个timestamp。为什么Rails不会转换它呢? - 23tux
我在下面讨论了类的问题,当你发表最新评论时,我正在撰写我的答案。 - mu is too short
1个回答

5
你的数据库将时间戳存储为UTC时间(这是正确的做法)。当ActiveRecord知道它有一个时间戳时,它会进行时区调整;因此,当你说:
puts Activity.first.starting_at

AR知道starting_at是一个时间戳,因此它将时间戳实例化为ActiveSupport :: TimeWithZone 实例,并且该类应用时区调整。但是,当你这样说时:
select("date_trunc('day', activities.starting_at) as date ...

AR不会解析SQL语句以确定date_trunc将返回时间戳,AR甚至不知道date_trunc的含义。 AR只会看到一个字符串从数据库中出来,它会无解释地把它交给你。您可以自由地将该字符串提供给ActiveSupport::TimeWithZone(或您喜欢的时间处理类):告诉AR自己不能知道的事情没有任何问题。Rails很聪明,但它不是魔法。

谢谢你的回答。我通过转储类找到了它。你会如何将字符串提供给ActiveSupport::TimeWithZone?遍历结果并转换字符串吗? - 23tux
你将会遍历结果,所以你可以把TimeWithZone的东西放在那里。不过我不是AR3范围大师,可能有更好的方法。 - mu is too short

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接