【问题标题】:Time zone changing arbitrarily时区任意变化
【发布时间】:2017-10-25 22:56:01
【问题描述】:

我正在使用 gem groupdate 在控制器的操作中执行这样的查询:

Event.where.not(user_id: [1, 3]).group_by_week(:created_at, week_start: :mon, last: 13, reverse: true).count

通过刷新网页执行几个顺序查询会不时更改 SQL 查询。似乎正在改变的是应用程序的默认时区,而我什至在此操作/视图中设置时区都没有发生这种情况。

这可能是什么原因?我如何/在哪里可以调试这个?

UTC 在application.rb 中设置为默认时区。上面同一个查询导致的两个不同 SQL 查询的例子:

SELECT COUNT(*) AS count_all, (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'Etc/UTC') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'Etc/UTC' AS date_trunc_week_created_at_timestamptz_interval_0_day_interval_ FROM "events" WHERE ("events"."user_id" NOT IN (1, 3, 290, 339)) AND (created_at >= '2017-07-31 00:00:00' AND created_at <= '2017-10-25 22:23:42.184226') GROUP BY (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'Etc/UTC') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'Etc/UTC'

SELECT COUNT(*) AS count_all, (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'America/New_York') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'America/New_York' AS date_trunc_week_created_at_timestamptz_interval_0_day_interval_ FROM "events" WHERE ("events"."user_id" NOT IN (1, 3, 290, 339)) AND (created_at >= '2017-07-31 04:00:00' AND created_at <= '2017-10-25 22:24:57.912750') GROUP BY (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'America/New_York') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'America/New_York'

【问题讨论】:

标签: ruby-on-rails postgresql ruby-on-rails-5 rails-activerecord


【解决方案1】:

方法def time_zone来自class Magic,它有一个attr_accessor :options。当您创建实例 @magic = Magic.new(period, options) 时,您在 options 参数中将您的时区设置为 truefalse 或其他值

基于此参数,def time_zone 方法将设置并返回 @time_zone

def time_zone
  @time_zone ||= begin
    time_zone = "Etc/UTC" if options[:time_zone] == false
    time_zone ||= options[:time_zone] || Groupdate.time_zone || (Groupdate.time_zone == false && "Etc/UTC") || Time.zone || "Etc/UTC"
    time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone[time_zone]
  end
end

您使用Groupdate.time_zone 设置时区。 :time_zone 是来自模块 Groupdate 的 attr_accessor

module Groupdate
  class Error < RuntimeError; end

  PERIODS = [:second, :minute, :hour, :day, :week, :month, :quarter, :year, :day_of_week, :hour_of_day, :minute_of_hour, :day_of_month, :month_of_year]
  # backwards compatibility for anyone who happened to use it
  FIELDS = PERIODS
  METHODS = PERIODS.map { |v| :"group_by_#{v}" } + [:group_by_period]

  mattr_accessor :week_start, :day_start, :time_zone, :dates
  self.week_start = :sun
  self.day_start = 0
  self.dates = true
end

这就是 magic.rb 内部的方法 def time_zone 正在搜索值的地方...

time_zone ||= options[:time_zone] || Groupdate.time_zone || (Groupdate.time_zone == false && "Etc/UTC") || Time.zone || "Etc/UTC"

从上面的表达式可以看出,它要么是来自Magic 实例的options[:time_zone],要么是来自Groupdate 模块的Groupdate.time_zone,或者是来自您的服务器的Time.zone,或者桌面,或Etc/UTC

所以我认为您可以通过遵循指南来解决这个问题,它为您提供了两种选择:

解决方案

Time Zones

默认时区是 Time.zone。更改为:

Groupdate.time_zone = "Pacific Time (US & Canada)"

User.group_by_week(:created_at, time_zone: "Pacific Time (US & Canada)").count
# {
#   Sun, 06 Mar 2016 => 70,
#   Sun, 13 Mar 2016 => 54,
#   Sun, 20 Mar 2016 => 80
# }

时区对象也可以。要查看 Rails 中可用时区的列表,请运行 rake time:zones:all。

【讨论】:

    猜你喜欢
    • 2017-10-09
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多