我在 Ruby-on-Rails 中有一个 Date 实例。我想将其转换为 UTC 时间的中午。 我该怎么办?
我认为这会起作用。
date = Date.new(2024, 10, 20)
time = date.to_time + Time.now.gmt_offset + 3600*12
# => 2024-10-20 12:00:00 +0100
time.utc
# => 2024-10-20 11:00:00 UTC
我认为它确实有效,但似乎不再有效;它给出的是 UTC 11 点,而不是 12 点...考虑到 1 小时的差异,我怀疑这与我的机器位于英国时区这一事实有关。 但怎么会呢?
过去的很多文章和问答都提到了 Ruby 中的DateTime。但是,DateTime 在 Ruby 中已被弃用(例如,请参阅 2020 年的本文)。所以,我想要一个时间。
在 Ruby 3 和 Rails 7 中实现这一目标的(最佳)方法是什么?
开门见山,使用 Rails 将
Date
转换为 UTC 中午 Time
的最简单、最清晰的方法可能是这样:
date = Date.new(2024, 10, 20)
date.to_time(:utc) + 12.hours
# => 2024-10-20 00:00:00 UTC
这里,Rails 中的
Date#to_time
可以选择接受 :local
(默认)或 :utc
(官方参考)参数,与原生 Ruby 不同。
请注意,默认选项 :local
的意思是:
Ruby 的进程时区,即
。如果需要应用程序的时区,请使用ENV['TZ']
代替。in_time_zone
这里解释了为什么您的示例代码不起作用;这是因为
Date#to_time
似乎也考虑到了这一点,其中时区实际上取决于在夏季和冬季时间之间定期切换的地区的日期。Date#to_time
转换为 BST(英国夏令时间)时区当天的 00:00。见下文:
Date.new(2024,10,20).to_time # => 2024-10-20 00:00:00 +0100
(夏令时)Date.new(2024,10,28).to_time # => 2024-10-28 00:00:00 +0000
(GMT=UTC)Time.now.gmt_offset
返回 0。Date.new(2024, 10, 20)
中与 UTC 的时间偏移现在未正确考虑,而当您在 BST 时区期间运行代码时却考虑到了。
Time.now.gmt_offset
的当前时间替换为当天的实际time:
date = Date.new(2024, 10, 20)
time = date.to_time
(time + time.gmt_offset + 3600*12).utc # ← use "time" instead of Time.now
# => 2024-10-20 12:00:00 UTC
# or similarly, but only in Rails:
(time + time.gmt_offset + 3600*12).in_time_zone("UTC") # in Rails only
(time + time.gmt_offset + 12.hours).utc # in Rails only
# => 2024-10-20 12:00:00 UTC
相关替代方式
date = Date.new(2024, 10, 20)
t = Time.new(date.year, date.mon, date.day, 12, in: "UTC")
t = Time.new(*(date.strftime("%Y %m %d 12").split.map(&:to_i)), in: "UTC")
t = Time.parse(date.strftime("%Y-%m-%d 12:00:00 UTC"))
# => 2024-10-20 12:00:00 UTC
# Rails only
t = Time.use_zone("UTC") do
midday = Time.zone.parse(date.to_s)+12.hours
end
# => <ActiveSupport::TimeWithZone> Sun, 20 Oct 2024 12:00:00.000000000 UTC +00:00
最后一个对 Time 使用两个 Rails 类方法(如过去的答案中所建议):Time.use_zone和Time.zone(注意,有点令人困惑,本机 Ruby 有一个实例方法Time#zone
,它返回时区的字符串)。