如何在Ruby on Rails中更改区域偏移量?

时间:2021-06-22 13:35:00

I have a variable foo that contains a time, lets say 4pm today, but the zone offset is wrong, i.e. it is in the wrong time zone. How do I change the time zone?

我有一个变量foo包含一个时间,假设今天下午4点,但是区域偏移是错误的,也就是说它在错误的时区。我如何改变时区?

When I print it I get

当我打印出来的时候

Fri Jun 26 07:00:00 UTC 2009

So there is no offset, and I would like to set the offset to -4 or Eastern Standard Time.

没有偏移量,我想把偏移量设为-4或东部标准时间。

I would expect to be able to just set the offset as a property of the Time object, but that doesn't seem to be available?

我希望能够将偏移量设置为时间对象的属性,但这似乎是不可用的?

11 个解决方案

#1


17  

You don't explicitly say how you get the actual variable but since you mention the Time class so I'll assume you got the time using that and I'll refer to that in my answer

你没有明确说明你是如何得到实际变量的,但既然你提到了时间类,所以我假设你有时间用它,我会在回答中提到它。

The timezone is actually part of the Time class (in your case the timezone is shown as UTC). Time.now will return the offset from UTC as part of the Time.now response.

时区实际上是Time类的一部分(在您的例子中,时区显示为UTC)。时间。现在将返回来自UTC的偏移量作为时间的一部分。现在的反应。

>> local = Time.now
=> 2012-08-13 08:36:50 +0000
>> local.hour
=> 8
>> local.min
=> 36
>> 


... in this case I happen to be in the same timezone as GMT

…在这种情况下,我碰巧和格林尼治标准时间在同一个时区

Converting between timezones

The easiest way that I've found is to change the offset using '+/-HH:MM' format to the getlocal method. Let's pretend I want to convert between the time in Dublin and the time in New York

我发现的最简单的方法是使用'+/-HH:MM'格式将偏移量更改为getlocal方法。假设我想在都柏林的时间和纽约的时间之间转换

?> 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

Assuming that 'EST' is the name of the Timezone for New York, as Dan points out sometimes 'EDT' is the correct TZ.

假设“EST”是纽约时区的名称,丹指出,有时“EDT”是正确的TZ。

#2


15  

If given:

如果给定:

2011-10-25 07:21:35 -700

you want:

你想要的:

2011-10-25 07:21:35 UTC

then do:

然后做:

Time.parse(Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')).to_s

#3


13  

This takes advantage of the fact that Time#asctime doesn't include the zone.

这利用了时间#asctime不包含区域这一事实。

Given a time:

给定一个时间:

>> time = Time.now
=> 2013-03-13 13:01:48 -0500

Force it to another zone (this returns an ActiveSupport::TimeWithZone):

强制它到另一个区域(这将返回一个ActiveSupport::TimeWithZone):

>> ActiveSupport::TimeZone['US/Pacific'].parse(time.asctime)
=> Wed, 13 Mar 2013 13:01:48 PDT -07:00

Note that the original zone is ignored completely. If I convert the original time to utc, the result will be different:

注意,原始区域被完全忽略。如果我将原始时间转换为utc,结果将会不同:

>> ActiveSupport::TimeZone['US/Pacific'].parse(time.getutc.asctime)
=> Wed, 13 Mar 2013 18:01:48 PDT -07:00

You can use to_time or to_datetime on the result to get a corresponding Time or DateTime.

您可以在结果上使用to_time或to_datetime来获得相应的时间或DateTime。

This question uses an interesting approach with DateTime#change to set the tz offset. (Remember that ActiveSupport makes it easy to convert between Time and DateTime.) The downside is that there's no DST detection; you have to do that manually by using TZInfo's current_period.

这个问题使用了DateTime#change的一种有趣的方法来设置tz偏移量。(请记住,ActiveSupport使得在时间和日期之间进行转换变得很容易。)缺点是没有DST检测;您必须通过使用TZInfo的current_period来手动执行。

#4


11  

...

>> 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

One note: make sure that the current time object is set to UTC time first, otherwise Ruby will try and convert the Time object to your local timezone, thus throwing the calculation. You can always get the adjusted time by applying ".utc" to the end of the above statements in that case.

注意:确保当前时间对象首先被设置为UTC时间,否则Ruby将尝试将时间对象转换为您的本地时区,从而抛出计算。你可以通过申请得到调整后的时间。在这种情况下,在上述语句的末尾加上utc。

#5


10  

For those that came across this while looking for a non-rails solution (as I did), TZInfo solved it for me...

对于那些在寻找非rails解决方案时遇到这个问题的人(就像我一样),TZInfo为我解决了这个问题……

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

This also handles DST, which is what I needed that wasn't handled above.

它还处理DST,这是我需要的,上面没有处理的。

See: http://tzinfo.rubyforge.org/

参见:http://tzinfo.rubyforge.org/

#6


5  

in you environment.rb search for the following line.

在你的环境。rb搜索如下一行。

# 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'

Keep in mind ActiveRecord and Rails always handle Time as UTC internally.

请记住,ActiveRecord和Rails总是在内部使用UTC处理时间。

#7


2  

I'm using Rails 2.0 before they added the code that makes weppos solution work. Here's what I did

在添加使weppos解决方案工作的代码之前,我正在使用Rails 2.0。这是我所做的

# 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)

I break the time down into a 10 element array, change the timezone and then convert the array back into a time.

我将时间分解为10个元素数组,更改时区,然后将数组转换回时间。

#8


1  

Here is what worked for me...

这是对我有用的东西……

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")

#9


0  

Option 1

选项1

Use date_time_attribute gem:

使用date_time_attribute宝石:

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

Option 2

选项2

If time is used as an attribute, you can use the same date_time_attribute gem:

如果时间被用作属性,您可以使用相同的date_time_attribute gem:

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

#10


0  

This is what I did, as I am not using Rails and don't want to use any non-core gems.

这就是我所做的,因为我没有使用Rails,也不想使用任何非核心的gem。

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)

#11


0  

It's probably a good idea to store the time as UTC and then show it in a specific time zone when it is displayed. Here's an easy way to do that (works in Rails 4, unsure about earlier versions).

最好将时间存储为UTC,然后在显示时显示在特定的时区。这里有一个简单的实现方法(适用于Rails 4,不确定早期版本)。

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

But if you really want to store it in a specific timezone, you can just set the initial Time object to itself.in_time_zone like this:

但是如果您真的想要将它存储在一个特定的时区,您可以将初始时间对象设置为它自己。in_time_zone是这样的:

t = t.in_time_zone("EST")

#1


17  

You don't explicitly say how you get the actual variable but since you mention the Time class so I'll assume you got the time using that and I'll refer to that in my answer

你没有明确说明你是如何得到实际变量的,但既然你提到了时间类,所以我假设你有时间用它,我会在回答中提到它。

The timezone is actually part of the Time class (in your case the timezone is shown as UTC). Time.now will return the offset from UTC as part of the Time.now response.

时区实际上是Time类的一部分(在您的例子中,时区显示为UTC)。时间。现在将返回来自UTC的偏移量作为时间的一部分。现在的反应。

>> local = Time.now
=> 2012-08-13 08:36:50 +0000
>> local.hour
=> 8
>> local.min
=> 36
>> 


... in this case I happen to be in the same timezone as GMT

…在这种情况下,我碰巧和格林尼治标准时间在同一个时区

Converting between timezones

The easiest way that I've found is to change the offset using '+/-HH:MM' format to the getlocal method. Let's pretend I want to convert between the time in Dublin and the time in New York

我发现的最简单的方法是使用'+/-HH:MM'格式将偏移量更改为getlocal方法。假设我想在都柏林的时间和纽约的时间之间转换

?> 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

Assuming that 'EST' is the name of the Timezone for New York, as Dan points out sometimes 'EDT' is the correct TZ.

假设“EST”是纽约时区的名称,丹指出,有时“EDT”是正确的TZ。

#2


15  

If given:

如果给定:

2011-10-25 07:21:35 -700

you want:

你想要的:

2011-10-25 07:21:35 UTC

then do:

然后做:

Time.parse(Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')).to_s

#3


13  

This takes advantage of the fact that Time#asctime doesn't include the zone.

这利用了时间#asctime不包含区域这一事实。

Given a time:

给定一个时间:

>> time = Time.now
=> 2013-03-13 13:01:48 -0500

Force it to another zone (this returns an ActiveSupport::TimeWithZone):

强制它到另一个区域(这将返回一个ActiveSupport::TimeWithZone):

>> ActiveSupport::TimeZone['US/Pacific'].parse(time.asctime)
=> Wed, 13 Mar 2013 13:01:48 PDT -07:00

Note that the original zone is ignored completely. If I convert the original time to utc, the result will be different:

注意,原始区域被完全忽略。如果我将原始时间转换为utc,结果将会不同:

>> ActiveSupport::TimeZone['US/Pacific'].parse(time.getutc.asctime)
=> Wed, 13 Mar 2013 18:01:48 PDT -07:00

You can use to_time or to_datetime on the result to get a corresponding Time or DateTime.

您可以在结果上使用to_time或to_datetime来获得相应的时间或DateTime。

This question uses an interesting approach with DateTime#change to set the tz offset. (Remember that ActiveSupport makes it easy to convert between Time and DateTime.) The downside is that there's no DST detection; you have to do that manually by using TZInfo's current_period.

这个问题使用了DateTime#change的一种有趣的方法来设置tz偏移量。(请记住,ActiveSupport使得在时间和日期之间进行转换变得很容易。)缺点是没有DST检测;您必须通过使用TZInfo的current_period来手动执行。

#4


11  

...

>> 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

One note: make sure that the current time object is set to UTC time first, otherwise Ruby will try and convert the Time object to your local timezone, thus throwing the calculation. You can always get the adjusted time by applying ".utc" to the end of the above statements in that case.

注意:确保当前时间对象首先被设置为UTC时间,否则Ruby将尝试将时间对象转换为您的本地时区,从而抛出计算。你可以通过申请得到调整后的时间。在这种情况下,在上述语句的末尾加上utc。

#5


10  

For those that came across this while looking for a non-rails solution (as I did), TZInfo solved it for me...

对于那些在寻找非rails解决方案时遇到这个问题的人(就像我一样),TZInfo为我解决了这个问题……

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

This also handles DST, which is what I needed that wasn't handled above.

它还处理DST,这是我需要的,上面没有处理的。

See: http://tzinfo.rubyforge.org/

参见:http://tzinfo.rubyforge.org/

#6


5  

in you environment.rb search for the following line.

在你的环境。rb搜索如下一行。

# 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'

Keep in mind ActiveRecord and Rails always handle Time as UTC internally.

请记住,ActiveRecord和Rails总是在内部使用UTC处理时间。

#7


2  

I'm using Rails 2.0 before they added the code that makes weppos solution work. Here's what I did

在添加使weppos解决方案工作的代码之前,我正在使用Rails 2.0。这是我所做的

# 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)

I break the time down into a 10 element array, change the timezone and then convert the array back into a time.

我将时间分解为10个元素数组,更改时区,然后将数组转换回时间。

#8


1  

Here is what worked for me...

这是对我有用的东西……

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")

#9


0  

Option 1

选项1

Use date_time_attribute gem:

使用date_time_attribute宝石:

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

Option 2

选项2

If time is used as an attribute, you can use the same date_time_attribute gem:

如果时间被用作属性,您可以使用相同的date_time_attribute gem:

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

#10


0  

This is what I did, as I am not using Rails and don't want to use any non-core gems.

这就是我所做的,因为我没有使用Rails,也不想使用任何非核心的gem。

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)

#11


0  

It's probably a good idea to store the time as UTC and then show it in a specific time zone when it is displayed. Here's an easy way to do that (works in Rails 4, unsure about earlier versions).

最好将时间存储为UTC,然后在显示时显示在特定的时区。这里有一个简单的实现方法(适用于Rails 4,不确定早期版本)。

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

But if you really want to store it in a specific timezone, you can just set the initial Time object to itself.in_time_zone like this:

但是如果您真的想要将它存储在一个特定的时区,您可以将初始时间对象设置为它自己。in_time_zone是这样的:

t = t.in_time_zone("EST")