Rails:在时区获取#beginning_of_day

Posted

技术标签:

【中文标题】Rails:在时区获取#beginning_of_day【英文标题】:Rails: get #beginning_of_day in time zone 【发布时间】:2011-07-22 02:34:23 【问题描述】:

我为 rails 应用程序设置了默认时区。 以及 Date 对象的一个​​实例。

如何让日期#beginning_of_day 返回指定时区的开始日期,而不是我的本地时区。

是否有任何其他方法可以在给定日期的指定时区获取一天的开始时间?

date = Date.new(2014,10,29)

zone = ActiveSupport::TimeZone.new('CET')
date.foo(zone) # should return "Wed, 29 Oct 2014 00:00:00 CET +01:00"

zone = ActiveSupport::TimeZone.new('UTC')
date.foo(zone) # should return "Wed, 29 Oct 2014 00:00:00 UTC +00:00"

【问题讨论】:

不管时区,一天的开始不是总是 00:00 吗? 总是 00:00,但 00:00 在不同时区总是不同的。 #beginning_of_day 的结果知道时区。似乎它选择本地时区而不是默认时区:Time.zone。 我在这个帖子线程中尝试了一些东西,它导致 UTC 以东时区的错误答案。我要发布一个“答案”,因为评论不会格式化代码。 @BogdanGusiev 我添加了一些示例。如果不是你的意思,请告诉我。 【参考方案1】:
DateTime.now.in_time_zone(Time.zone).beginning_of_day

【讨论】:

【参考方案2】:
time_zone = Time.zone # any time zone really
time_zone.local(date.year, date.month, date.day)

问题是,Date.beginning_of_day 在 ActiveSupport 2.3 中不支持 Time.zone

比较https://github.com/rails/rails/blob/v2.3.11/activesupport/lib/active_support/core_ext/date/calculations.rb#L64 (AS 2.3)

到https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/date/calculations.rb#L74 和 https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/date/zones.rb#L7 (AS 3)

【讨论】:

它现在在 4.1 中对我有用,Time.now.beginning_of_dayDate.today.beginning_of_day 都使用我的应用程序时区返回正确的时间 我尝试了date.localtime.beginning_of_day,似乎选择了当地时区【参考方案3】:

Date#beginning_of_day 将始终返回 00:00。

但据我了解,您想知道其他时区的时间,而当前时区是一天的开始。

所以。让我们找出您当前位置的一天的开始。想象一下它是法国巴黎:

bd = DateTime.now.in_time_zone('Paris').beginning_of_day
# or just
bd = DateTime.now.in_time_zone(1).beginning_of_day
#=> Thu, 24 Mar 2011 00:00:00 WET +01:00

现在让我们看看莫斯科的时间:

moscow_time = bd.in_time_zone("Moscow") # or in_time_zone(3)
#=> Thu, 24 Mar 2011 02:00:00 AST +03:00
london_time = bd.in_time_zone("London")
#=> Wed, 23 Mar 2011 23:00:00 GMT +00:00
kyiv_time = bd.in_time_zone("Kyiv")
#=> Thu, 24 Mar 2011 01:00:00 EET +02:00 

对于不同的形式nowday:

# You even shouldn't call now, because it by default will be 00:00
date = DateTime(2011, 1, 3).in_time_zone("-10")
# or
date = DateTime.new(2011,1,3,0,0,0,"-10")
# and same way as above
moscow_time = date.in_time_zone("Moscow") # or in_time_zone(3)

并将Date 转换为DateTime

date = Date.new(2011,1,3).to_datetime.change(:offset => "EST")

【讨论】:

是否可以为自定义日期执行此操作,而不仅仅是今天? 是的,当然,2011 年 1 月 3 日:bd = DateTime.new(2011, 1, 3).in_time_zone('Paris').beginning_of_day 等等 Try it before post 听起来不友好,波格丹 我同意@fl00r 这里@Bogdan...让我们保持文明,记住人们在这里帮助你。 您误解了这个问题。问题不是,如果它是 X 时区的 00:00,它在 Y 时区是几点钟。问题是,Y 时区的一天的开始时间是什么时候。(用时区表示,或UTC)。【参考方案4】:

离开 Peder 的回答,这是我为 PST 时区所做的:

DateTime.now.in_time_zone("Pacific Time (US & Canada)").beginning_of_day

【讨论】:

【参考方案5】:
may2 = Date.new(2012,5,2)
midnight = Time.zone.local(may2.year,may2.month,may2.day).beginning_of_day

2012 年 5 月 2 日星期三 00:00:00 UTC +00:00

midnight = Time.zone.local(may2.year,may2.month,may2.day).in_time_zone("Moscow").beginning_of_day

=> 2012 年 5 月 2 日,星期三 00:00:00 MSK +04:00

midnight = Time.zone.local(may2.year,may2.month,may2.day).in_time_zone("Alaska").beginning_of_day

=> 2012 年 5 月 1 日星期二 00:00:00 AKDT -08:00

注意,今天是错误的一天。

需要一种在正确时区构造 TimeWithZone 的方法。

Time.zone="Alaska"
midnight = Time.zone.local(may2.year,may2.month,may2.day)

我真的不喜欢这个,因为据我所知,我刚刚更改了我所在区域的 system 概念。想法是更改我的数据库搜索以匹配客户区... 所以,我必须保存区域并恢复它:

foo = Time.zone; Time.zone="Alaska"; midnight = Time.zone.local(may2.year,may2.month,may2.day); Time.zone = foo

似乎我应该能够调用 TimeWithZone.new(),但我不知道如何。

【讨论】:

【参考方案6】:

我知道这篇文章已经过时了,但是呢:

Time.zone.parse("12am")

【讨论】:

【参考方案7】:
ActiveSupport::TimeZone['Europe/London'].parse('30.07.2013') # 2013-07-29 23:00:00 UTC 
ActiveSupport::TimeZone['Asia/Magadan'].parse('30.07.2013') # 2013-07-29 12:00:00 UTC

【讨论】:

【参考方案8】:

正如 Leonid Shevtsov 所说,Date.beginning_of_day 在 ActiveSupport 2.3 中不尊重 Time.zone

如果您坚持使用 Rails 4.0 或 ActiveSupport 2.3,并且您需要使用自定义日期,我使用的替代方法:

date = Date.new(2014,10,29)
date.to_time.change(hour: 0, min: 0, sec: 0).in_time_zone  #.beginning_of_day
date.to_time.change(hour: 23, min: 59, sec: 59).in_time_zone #.end_of_day

结果:

2.0.0-p247 :001 > date = Date.new(2014,10,29)
 => Wed, 29 Oct 2014 

2.0.0-p247 :002 > date.to_time.change(hour: 0, min: 0, sec: 0)
 => 2014-10-29 00:00:00 -0500 

2.0.0-p247 :003 > date.to_time.change(hour: 0, min: 0, sec: 0).in_time_zone
 => Wed, 29 Oct 2014 05:00:00 UTC +00:00 

2.0.0-p247 :004 > date.to_time.change(hour: 23, min: 59, sec: 59)
 => 2014-10-29 23:59:59 -0500 

2.0.0-p247 :005 > date.to_time.change(hour: 23, min: 59, sec: 59).in_time_zone
 => Thu, 30 Oct 2014 04:59:59 UTC +00:00 

我最初使用 .beginning_of_day 到 .end_of_day 的失败模型范围无法正常工作:

scope :on_day, ->(date)  where( created_at: date.beginning_of_day..date.end_of_day ) 

而且,这是修复它的原因,因为我无法升级到 Rails 4.0

scope :on_day, ->(date)  where( created_at: date.to_time.change(hour: 0, min: 0, sec: 0).in_time_zone..date.to_time.change(hour: 23, min: 59, sec: 59).in_time_zone ) 

【讨论】:

以上是关于Rails:在时区获取#beginning_of_day的主要内容,如果未能解决你的问题,请参考以下文章

Rails:使用Heroku时如何获取当前用户的时区

在 Rails 和 PostgreSQL 中完全忽略时区

在转换为UTC 0时区之前,Rails在哪里获得时区?

在 Rails 中,如何以可与 ActiveSupport::TimeZone[zone].parse() 一起使用的格式获取当前时区 (Time.zone)?

Ruby 时区——到 UTC 并返回

根据国家名称转换时区 rails 4