【问题标题】:Rails doesn't convert timezone (PostgreSQL)Rails 不转换时区 (PostgreSQL)
【发布时间】:2011-04-20 22:45:47
【问题描述】:

我对时区和 postgresql 数据库(Rails 3.0.4、PostgreSQL 9.0)有疑问。我正在使用自定义范围,我在其中附加了一些条件,进行连接 etc.pp。

问题是,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)

并且在选择语句中,我想将starting_at字段截断为day。

我得到以下日期字段的输出:

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

我做错了什么?希望有人能帮忙!

谢谢, 晚礼服

【问题讨论】:

  • 数据库中activities.starting_at是什么类型?如果你在psql 内部select starting_at from activities 会发生什么?
  • activities.starting_attimestamp without a timezone(以 UTC 格式存储)。 select starting_at from activities 返回2011-04-15 04:47:34,也没有时区。但是 Rails 不应该即时将时间转换为特定的时区吗?以我的问题puts Activity.first.starting_at -&gt; 2011-04-15 06:47:55 +0200 中的示例为例,它可以工作。
  • 我发现了另一个有趣的事情:当我尝试迭代结果并转储我的日期字段的类时,我得到String。但它应该是ActiveSupport::TimeWithZone。我阅读了 postgresql 的文档,date_trunc('day', activities.starting_at) 应该返回一个timestamp。为什么 Rails 不转换这个?
  • 我涵盖了下面的课程问题,我在您发表最新评论时正在写答案。

标签: ruby-on-rails ruby-on-rails-3 postgresql timestamp rails-postgresql


【解决方案1】:

您的数据库正在以 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”?遍历结果并转换字符串?
  • 无论如何你都会遍历结果,这样你就可以把 TimeWithZone 的东西放在那里。我不是 AR3 范围专家,所以可能有更好的方法。
猜你喜欢
  • 1970-01-01
  • 2014-07-02
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-17
  • 2021-02-10
  • 1970-01-01
相关资源
最近更新 更多