Как изменить смещение зоны на время в Ruby on Rails?
У меня есть переменная foo, которая содержит время, скажем, 4 вечера сегодня, но смещение зоны неверно, то есть оно находится в неправильном часовом поясе. Как изменить часовой пояс?
Когда я печатаю его, я получаю
Fri Jun 26 07:00:00 UTC 2009
Итак, смещения нет, и я хотел бы установить смещение на -4 или восточное стандартное время.
Я ожидал бы, что сможет просто установить смещение как свойство объекта Time, но это кажется недоступным?
Ответы
Ответ 1
Я использую 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 элементов, изменяю часовой пояс и затем преобразую массив обратно во время.
Ответ 2
Вы явно не говорите, как вы получаете фактическую переменную, но поскольку вы упоминаете класс 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
Преобразование между часовыми поясами
Самый простой способ, который я нашел, - изменить смещение с использованием формата "+/- 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
Предполагая, что "EST" - это название часовой пояс для Нью-Йорка, как указывает Дэн, иногда "EDT" является правильной TZ.
Ответ 3
Если дано:
2011-10-25 07:21:35 -700
вы хотите:
2011-10-25 07:21:35 UTC
то do:
Time.parse(Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')).to_s
Ответ 4
Это использует тот факт, что 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 offset. (Помните, что ActiveSupport упрощает преобразование между Time
и DateTime
.) Недостатком является то, что нет обнаружения DST; вы должны сделать это вручную, используя TZInfo current_period
.
Ответ 5
...
>> 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" до конца вышеуказанных утверждений в этом случае.
Ответ 6
Для тех, кто сталкивался с этим при поиске решения без рельсов (как и я), 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/
Ответ 7
в вашем окружении .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 внутри.
Ответ 8
Вот что сработало для меня...
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
Вариант 1
Используйте атрибут 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
Вариант 2
Если время используется как атрибут, вы можете использовать тот же 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
Это то, что я сделал, поскольку я не использую Rails и не хочу использовать какие-либо неосновные драгоценные камни.
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
Вероятно, рекомендуется хранить время в формате 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 на self.in_time_zone следующим образом:
t = t.in_time_zone("EST")