Ruby/Rails - 更改时间的时区,而不更改值

rwb*_*rwb 95 ruby time timezone datetime ruby-on-rails

我foo在数据库中有一个记录:start_time和:timezone属性.

例如,:start_time是UTC时间2001-01-01 14:20:00.这:timezone是一个字符串 - America/New_York例如.

我想创建一个新的Time对象,其值为,:start_time但其时区由其指定:timezone.我不想加载:start_time然后转换为:timezone,因为Rails会很聪明并且从UTC更新时间以与该时区保持一致.

目前,

t = foo.start_time
=> 2000-01-01 14:20:00 UTC
t.zone
=> "UTC"
t.in_time_zone("America/New_York")
=> Sat, 01 Jan 2000 09:20:00 EST -05:00
Run Code Online (Sandbox Code Playgroud)

相反,我想看到

=> Sat, 01 Jan 2000 14:20:00 EST -05:00
Run Code Online (Sandbox Code Playgroud)

即.我想要做:

t
=> 2000-01-01 14:20:00 UTC
t.zone = "America/New_York"
=> "America/New_York"
t
=> 2000-01-01 14:20:00 EST
Run Code Online (Sandbox Code Playgroud)

Fre*_*ung 63

听起来你想要的东西沿着这条线

ActiveSupport::TimeZone.new('America/New_York').local_to_utc(t)
Run Code Online (Sandbox Code Playgroud)

这表示将此本地时间(使用区域)转换为utc.如果你已经Time.zone设定,那么你当然可以

Time.zone.local_to_utc(t)
Run Code Online (Sandbox Code Playgroud)

这不会使用附加到t的时区 - 它假定它是您要转换的时区的本地区域.

这里要防范的一个边缘案例是DST转换:您指定的本地时间可能不存在或可能不明确.

  • 我需要local_to_utc和Time.use_zone的组合:`Time.use_zone(self.timezone){Time.zone.local_to_utc(t)}.localocal` (15认同)

Zhe*_*nya 22

我刚遇到同样的问题,这就是我要做的事情:

t = t.asctime.in_time_zone("America/New_York")
Run Code Online (Sandbox Code Playgroud)

这是关于asctime的文档

  • 正是我所期望的 (2认同)

Bri*_*ian 20

如果你正在使用Rails,这是另一种方法,就像Eric Walsh的回答一样:

def set_in_timezone(time, zone)
  Time.use_zone(zone) { time.to_datetime.change(offset: Time.zone.now.strftime("%z")) }
end
Run Code Online (Sandbox Code Playgroud)


j_m*_*lly 8

您需要在转换后将时间偏移量添加到您的时间.

最简单的方法是:

t = Foo.start_time.in_time_zone("America/New_York")
t -= t.utc_offset
Run Code Online (Sandbox Code Playgroud)

我不确定你为什么要这样做,尽管实际上最好与它们的构建方式一起工作.我想一些关于为什么需要改变时间和时区的背景会有所帮助.


Pet*_*vin 5

实际上,我认为您需要在转换后减去偏移量,如下所示:

1.9.3p194 :042 > utc_time = Time.now.utc
=> 2013-05-29 16:37:36 UTC
1.9.3p194 :043 > local_time = utc_time.in_time_zone('America/New_York')
 => Wed, 29 May 2013 12:37:36 EDT -04:00
1.9.3p194 :044 > desired_time = local_time-local_time.utc_offset
 => Wed, 29 May 2013 16:37:36 EDT -04:00 
Run Code Online (Sandbox Code Playgroud)