Подтвердить что ты не робот

Как изменить смещение зоны на время в Ruby on Rails?

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

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

Fri Jun 26 07:00:00 UTC 2009

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

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

4b9b3361

Ответ 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")