1

我正在开发 Rails 应用程序,该应用程序允许用户每天最多发布 2 个帖子,非常简单。

我的问题是如何管理不同用户居住的不同时区。例如,如果我住在伦敦,一天开始00.00和结束23.59的帖子计数将重置为00.00,但对于住在纽约的其他用户,计数器将在不同的时间重置。(不在00.00)我该如何处理这种情况?

我希望我自己解释。

更新 1

@簇

您的代码的问题是time_zone.utc_offset给出了错误的时间增量:

1.9.3p194 :123 > time_zone = ActiveSupport::TimeZone.new("Prague")
 => (GMT+01:00) Prague 
1.9.3p194 :124 > DateTime.now.utc.midnight - time_zone.utc_offset
 => Thu, 10 Apr 2003 00:00:00 +0000 

为什么?

相反,我发现这段代码很有用:

User.posts.where(:created_at => DateTime.now.in_time_zone(time_zone).beginning_of_day..DateTime.now.in_time_zone(time_zone).end_of_day).count

它似乎在用户当天(使用用户的时区)之间获得了正确数量的消息。你怎么看?

更新 2

@簇

有什么区别:

User.posts.where(:created_at => DateTime.now.in_time_zone(utc_time_zone).beginning_of_day..DateTime.now.in_time_zone(utc_time_zone).end_of_day).count

你的呢:

1.9.3p327 :015 > time_zone = ActiveSupport::TimeZone.new("Prague")
 => (GMT+01:00) Prague 
1.9.3p327 :016 > Time.zone.now.utc.midnight - time_zone.utc_offset
 => 2013-02-15 23:00:00 UTC

在性能和做事方式方面?

更新 3

实际上,您示例中的代码不起作用,请看这里:

# WRONG
1.9.3p194 :096 > user.posts.where('created_at > ?', Time.zone.now.utc.midnight - my_time_zone.utc_offset).count
   (0.2ms)  SELECT COUNT(*) FROM "messages" WHERE "messages"."sender_id" = 5 AND (created_at > '2013-02-15 23:00:00.000000')
 => 4 

# CORRECT
1.9.3p194 :098 > users.posts.where(:created_at => DateTime.now.in_time_zone(my_time_zone).beginning_of_day..DateTime.now.in_time_zone(my_time_zone).end_of_day).count
   (0.3ms)  SELECT COUNT(*) FROM "messages" WHERE "messages"."sender_id" = 5 AND ("messages"."created_at" BETWEEN '2013-02-16 23:00:00.000000' AND '2013-02-17 22:59:59.000000')
 => 0
4

2 回答 2

4

根据您希望它的工作方式,我可以想到两种解决方案。

首先,允许用户在 24 小时内发布两次,这样做的好处是与时区无关:

User.posts.where('created_at > ?', 24.hours.ago).count

如果返回 2,则不要让他们发布。

如果你真的想确保每天不超过 2 个帖子,那么:

time_zone = ActiveSupport::TimeZone.new(current_user.time_zone)
Users.posts.where('created_at > ?', Time.zone.now.utc.midnight - time_zone.utc_offset).count

User#time_zone 需要持有 Rails 识别的有效时区。

由于数据库日期时间 (created_at) 已经采用 UTC,首先将服务器时间标准化为 utc,然后将时间设置为午夜,并为时区应用 utc 偏移量。因此,如果您有人在 -7 时区,那么它将查找自 0700 UTC 以来的帖子,对于处于 +3 时区的人,它将查找自 2100 UTC 以来的帖子。

ActiveSupport::时区

为了阐明两者之间的区别,让我举几个例子。

第一个示例是用户在 1200 发帖,然后在周一又在 1800 发帖。

使用第一段代码,用户将无法在星期二 0600 之后再次发布。使用第二段代码,他们将能够在星期二 0000(午夜之后)再次发布。

第二个示例是用户在 2330 发帖,然后在周一的 2350 发帖。同样,在第一个示例中,他们将在星期二 2330 之后才能再次发布,但第二个示例将允许他们在午夜再次发布,允许他们在 0010 和 0020 发布,在 50 分钟内给他们 4 个帖子。

这实际上取决于职位限制的目的是什么。第一个示例将更易于使用和实现,因为它可以在不受时区影响的情况下工作。

如果您从 FB 提取时区信息,请检查该时区信息的格式。我猜它不会是一个ActiveSupport::TimeZone可以接受的有效字符串。例如,它"Mountain Time (US & Canada)"需要 MST(-0700)。如果 FB 为您返回类似 MST 的 -7 或 -25200(-7 小时以秒为单位)之类的东西,那么您可以使用这些东西而无需使用 AS:TZ

回复:更新 1

这是使用 Time.zone 而不是 DateTime 的输出

1.9.3p327 :015 > time_zone = ActiveSupport::TimeZone.new("Prague")
 => (GMT+01:00) Prague 
1.9.3p327 :016 > Time.zone.now.utc.midnight - time_zone.utc_offset
 => 2013-02-15 23:00:00 UTC
于 2013-02-16T20:06:14.560 回答
0

考虑为每个人使用 UTC 时区。即 StackOverflow 使用这种方法进行投票,并且效果很好。

于 2013-02-16T19:12:49.543 回答