Как изменить зону смещения на некоторое время в Ruby On Rails? - PullRequest
24 голосов
/ 26 июня 2009

У меня есть переменная foo, которая содержит время, скажем, 4 часа дня сегодня, но смещение зоны неправильное, то есть оно находится в неправильном часовом поясе. Как мне изменить часовой пояс?

Когда я печатаю его, я получаю

Fri Jun 26 07:00:00 UTC 2009

То есть смещения нет, и я хотел бы установить смещение на -4 или восточное стандартное время.

Я ожидал бы, что смогу просто установить смещение как свойство объекта Time, но это, по-видимому, недоступно?

Ответы [ 12 ]

17 голосов
/ 26 июня 2009

Вы не говорите явно, как вы получаете фактическую переменную, но так как вы упоминаете класс Time, поэтому я предполагаю, что вы получили время, используя это, и я буду ссылаться на это в моем ответе

Часовой пояс фактически является частью класса Time (в вашем случае часовой пояс отображается как UTC). Time.now вернет смещение от UTC как часть ответа Time.now.

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


... в этом случае я нахожусь в том же часовом поясе, что и GMT

Преобразование часовых поясов

Самый простой способ, который я нашел, - это изменить смещение с помощью формата +/- ЧЧ: ММ на метод 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

Предполагая, что «EST» - это название часового пояса для Нью-Йорка, как указывает Дэн, иногда «EDT» - это правильный TZ.

15 голосов
/ 25 октября 2011

Если дано:

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

Вы хотите:

2011-10-25 07:21:35 UTC

затем выполните:

Time.parse(Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')).to_s
14 голосов
/ 13 марта 2013

Это использует тот факт, что Time#asctime не включает зону.

Дано время:

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

Перевести его в другую зону (возвращается ActiveSupport::TimeWithZone):

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

Обратите внимание, что исходная зона полностью игнорируется. Если я преобразую исходное время в utc, результат будет другим:

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

Вы можете использовать to_time или to_datetime в результате, чтобы получить соответствующий Time или DateTime.

В этом вопросе используется интересный подход с DateTime#change для установки смещения tz. (Помните, что ActiveSupport позволяет легко конвертировать между Time и DateTime.) Недостатком является отсутствие обнаружения DST; Вы должны сделать это вручную, используя TZInfo's current_period.

11 голосов
/ 08 июня 2010

...

>> 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» к концу вышеприведенных операторов.

10 голосов
/ 28 мая 2012

Для тех, кто сталкивался с этим во время поиска решения, не связанного с рельсами (как я это сделал), 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

Это также обрабатывает DST, то, что мне было нужно, которое не было обработано выше.

См .: http://tzinfo.rubyforge.org/

5 голосов
/ 26 июня 2009

в вас environment.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'

Имейте в виду, что ActiveRecord и Rails всегда обрабатывают время как UTC внутри.

2 голосов
/ 28 июня 2009

Я использую Rails 2.0 до того, как они добавили код, который заставляет работать решение weppos. Вот что я сделал

# 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 голос
/ 27 июля 2009

Вот что у меня сработало ...

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")
0 голосов
/ 20 октября 2018

При разборе времени

Мне было бы интересно услышать, как вы устанавливаете переменную foo для начала.

Если вы анализируете строку времени, у которой нет часового пояса (что я делал во время импорта данных), тогда вы можете использовать String#in_time_zone для принудительной установки часового пояса во время анализа :

"Fri Jun 26 2019 07:00:00".in_time_zone( "Eastern Time (US & Canada)" ) 
# => Wed, 26 Jun 2019 07:00:00 EDT -04:00

Работает как шарм и очень чистый.

0 голосов
/ 21 апреля 2016

Вероятно, хорошей идеей будет сохранить время в формате 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

Но если вы действительно хотите сохранить его в определенном часовом поясе, вы можете просто установить начальный объект Time в себя. In_time_zone следующим образом:

t = t.in_time_zone("EST")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...