How do I change the zone offset for a time in Ruby on Rails?
我有一个包含时间的变量foo,比如今天下午4点,但是区域偏移是错误的,即它在错误的时区。 如何更改时区?
当我打印它时,我得到了
1 | Fri Jun 26 07:00:00 UTC 2009 |
所以没有偏移,我想将偏移设置为-4或东部标准时间。
我希望能够将偏移量设置为Time对象的属性,但这似乎不可用?
你没有明确说明你是如何获得实际变量的,但是因为你提到了Time类所以我假设你有时间使用它,我会在我的回答中提到
时区实际上是Time类的一部分(在您的情况下,时区显示为UTC)。 Time.now将返回UTC的偏移量作为Time.now响应的一部分。
1 2 3 4 5 6 7 | >> local = Time.now => 2012-08-13 08:36:50 +0000 >> local.hour => 8 >> local.min => 36 >> |
......在这种情况下,我碰巧与GMT在同一时区
在时区之间转换
我发现最简单的方法是使用'+/- HH:MM'格式将偏移量更改为getlocal方法。让我假装我想在都柏林和纽约时间之间进行转换
1 2 3 4 5 6 7 8 | ?> dublin = Time.now => 2012-08-13 08:36:50 +0000 >> new_york = dublin + Time.zone_offset('EST') => 2012-08-13 08:36:50 +0000 >> dublin.hour => 8 >> new_york.hour => 3 |
假设'EST'是纽约时区的名称,Dan指出有时'EDT'是正确的TZ。
如果给出:
1 | 2011-10-25 07:21:35 -700 |
你要:
1 | 2011-10-25 07:21:35 UTC |
然后做:
1 | Time.parse(Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')).to_s |
这利用了
给定时间:
1 2 | >> time = Time.now => 2013-03-13 13:01:48 -0500 |
强制它到另一个区域(返回
1 2 | >> ActiveSupport::TimeZone['US/Pacific'].parse(time.asctime) => Wed, 13 Mar 2013 13:01:48 PDT -07:00 |
请注意,原始区域将被完全忽略。如果我将原始时间转换为utc,结果将会有所不同:
1 2 | >> ActiveSupport::TimeZone['US/Pacific'].parse(time.getutc.asctime) => Wed, 13 Mar 2013 18:01:48 PDT -07:00 |
您可以在结果上使用
这个问题使用一种有趣的方法,用
...
1 2 3 4 5 6 | >> Time.at(Time.now.utc + Time.zone_offset('PST')) => Mon Jun 07 22:46:22 UTC 2010 >> Time.at(Time.now.utc + Time.zone_offset('PDT')) => Mon Jun 07 23:46:26 UTC 2010 >> Time.at(Time.now.utc + Time.zone_offset('CST')) => Tue Jun 08 00:46:32 UTC 2010 |
注意:确保当前时间对象首先设置为UTC时间,否则Ruby将尝试将Time对象转换为您的本地时区,从而抛出计算。在这种情况下,您可以通过在上述语句的末尾应用".utc"来获得调整时间。
对于那些在寻找非导轨解决方案时遇到这种情况的人(就像我一样),TZInfo为我解决了这个问题......
1 2 3 4 5 6 7 8 9 | require 'tzinfo' def adjust_time time, time_zone="America/Los_Angeles" return TZInfo::Timezone.get(time_zone).utc_to_local(time.utc) end puts adjust_time(Time.now) #=> PST or PDT puts adjust_time(Time.now,"America/New_York") #=> EST or EDT |
这也处理DST,这是我需要的,上面没有处理。
见:http://tzinfo.rubyforge.org/
在你的environment.rb中搜索以下行。
1 2 3 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run"rake -D time" for a list of tasks for finding time zone names. config.time_zone = 'UTC' |
请记住,ActiveRecord和Rails始终在内部处理时间为UTC。
我在使用Rails 2.0之前添加了使weppos解决方案工作的代码。这就是我做的
1 2 3 4 5 | # Silly hack, because sometimes the input_date is in the wrong timezone temp = input_date.to_time.to_a temp[8] = true temp[9] ="Eastern Daylight Time" input_date = Time.local(*temp) |
我将时间分解为10个元素数组,更改时区,然后将数组转换回时间。
这对我有用...
1 2 3 4 5 6 7 8 9 | def convert_zones(to_zone) to_zone_time = to_zone.localtime end # have your time set as time time = convert_zones(time) time.strftime("%b #{day}, %Y (%a) #{hour}:%M %p %Z") |
解析时间
我很想知道你是如何设置变量
如果您正在解析没有时区的时间字符串(在数据导入期间我正在做什么),那么您可以在解析期间使用
1 2 | "Fri Jun 26 2019 07:00:00".in_time_zone("Eastern Time (US & Canada)" ) # => Wed, 26 Jun 2019 07:00:00 EDT -04:00 |
像魅力一样工作,超级干净。
将时间存储为UTC然后在显示时在特定时区显示它可能是个好主意。这是一个简单的方法(在Rails 4中工作,不确定早期版本)。
1 2 3 4 5 6 7 | t = Time.now.utc => 2016-04-19 20:18:33 UTC t.in_time_zone("EST") => Tue, 19 Apr 2016 15:18:33 EST -05:00 |
但是如果你真的想将它存储在特定的时区,你可以将初始Time对象设置为self.in_time_zone,如下所示:
1 | t = t.in_time_zone("EST") |
这就是我所做的,因为我没有使用Rails而且不想使用任何非核心宝石。
1 2 3 4 | t = Time.now # my local time - which is GMT zone_offset = 3600 # offset for CET - which is my target time zone zone_offset += 3600 if t.dst? # an extra hour offset in summer time_cet = Time.mktime(t.sec, t.min, t.hour, t.mday, t.mon, t.year, nil, nil, t.dst?, zone_offset) |
选项1
使用date_time_attribute gem:
1 2 3 4 | my_date_time = DateTimeAttribute::Container.new(Time.zone.now) my_date_time.date_time # => 2001-02-03 22:00:00 KRAT +0700 my_date_time.time_zone = 'Moscow' my_date_time.date_time # => 2001-02-03 22:00:00 MSK +0400 |
选项2
如果将time用作属性,则可以使用相同的date_time_attribute gem:
1 2 3 4 5 6 7 8 9 10 | class Task include DateTimeAttribute date_time_attribute :due_at end task = Task.new task.due_at_time_zone = 'Moscow' task.due_at # => Mon, 03 Feb 2013 22:00:00 MSK +04:00 task.due_at_time_zone = 'London' task.due_at # => Mon, 03 Feb 2013 22:00:00 GMT +00:00 |