Преобразование времени из одного часового пояса в другой в Rails

105

Мои created_atвременные метки хранятся в UTC:

>> Annotation.last.created_at
=> Sat, 29 Aug 2009 23:30:09 UTC +00:00

Как перевести один из них на «восточное время (США и Канада)» (с учетом летнего времени)? Что-то вроде:

Annotation.last.created_at.in_eastern_time
Том Леман
источник

Ответы:

191

Используйте метод in_time_zone класса DateTime

Loading development environment (Rails 2.3.2)
>> now = DateTime.now.utc
=> Sun, 06 Sep 2009 22:27:45 +0000
>> now.in_time_zone('Eastern Time (US & Canada)')
=> Sun, 06 Sep 2009 18:27:45 EDT -04:00
>> quit

Итак, для вашего конкретного примера

Annotation.last.created_at.in_time_zone('Eastern Time (US & Canada)')
Стив Уит
источник
7
или вы можете просто использовать часовой идентификаторnow.in_time_zone(3)
fl00r
8
created_at.in_time_zone("EST")короче
Орландо
51
"EST" = "Eastern Standard Time", поэтому при переходе на летнее время будет неправильно. «Восточное время (США и Канада)» выясняет, летнее время сейчас или нет.
jhiro009
1
Обратите внимание, что метод in_time_zone является частью ActiveSupport, поэтому он встроен в Rails, но не является частью stdlib Ruby. Если у вас есть приложение для рельсов, нет проблем. Если у вас есть обычное приложение Ruby, вам обязательно потребуется активная поддержка.
Gayle
Ссылка на документацию по этому методу находится здесь: apidock.com/rails/DateTime/in_time_zone
Naved Khan
17

Хотя это старый вопрос, о нем стоит упомянуть. В предыдущем ответе предлагалось использовать before_filter для временной установки часового пояса.

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

Вместо этого вы должны использовать around_filter, чтобы убедиться, что Time.zone сбрасывается после завершения запроса. Что-то вроде:

around_filter :set_time_zone

private

def set_time_zone
  old_time_zone = Time.zone
  Time.zone = current_user.time_zone if logged_in?
  yield
ensure
  Time.zone = old_time_zone
end

Подробнее об этом читайте здесь

Opsidao
источник
1
Сейчас есть хороший метод Time.use_zone .
Freemanoid
9

Если вы добавите это в свой /config/application.rb

config.time_zone = 'Eastern Time (US & Canada)'

Тогда вы можете сотовый

Annotation.last.created_at.in_time_zone

чтобы получить время в указанном часовом поясе.

Эйфион
источник
если мы настраиваем часовой пояс в application.rb, тогда не нужно вызывать ".in_time_zone". rails автоматически делают это за нас, нужно позвонить Annotation.last.created_at
Vishal
3

Если вы настроите свой /config/application.rb

config.time_zone = 'Eastern Time (US & Canada)'

Time.now.in_time_zone

DateTime.now.in_time_zone
Дориан
источник
2

Установите часовой пояс на восточное время.

Вы можете установить часовой пояс по умолчанию в config / environment.rb

config.time_zone = "Eastern Time (US & Canada)"

Теперь все извлеченные вами записи будут в этом часовом поясе. Если вам нужны разные часовые пояса, скажем, на основе часового пояса пользователя, вы можете изменить его с помощью before_filter в вашем контроллере.

class ApplicationController < ActionController::Base

  before_filter :set_timezone

  def set_timezone
    Time.zone = current_user.time_zone
  end
end

Просто убедитесь, что вы все свое время храните в базе данных как UTC, и все будет хорошо.

ниткодер
источник
Имеет ли это значение, если вы используете сервер приложений, такой как дворняга, тонкий или пассажирский? Они запускают более одного экземпляра, я полагаю, однопоточный? Я могу ошибаться, хотелось бы знать!
nitecoder
4
Time.zone=является потокобезопасным github.com/rails/rails/blob/master/activesupport/lib/… .
lest
Может, этого не было в 2009 году?
nitecoder
2
@jpwynn: в соответствии с этим: github.com/rails/rails/commit/… это потокобезопасность уже более 5 лет. Любой источник или пример вашей проблемы?
Паскаль
1
Поток может обслуживать несколько сеансов. Если вы устанавливаете его один раз, когда пользователь входит в систему, например, ПОСЛЕДНИЙ пользователь, вошедший в систему, установит часовой пояс для ВСЕХ пользователей, сеанс которых использует тот же поток. Таким образом, вы ДОЛЖНЫ использовать before_filter, чтобы устанавливать его для каждого пользователя при каждой загрузке страницы.
jpw