Converter o tempo de um fuso horário para outro no Rails

105

Meus created_atcarimbos de data / hora são armazenados em UTC:

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

Como faço para converter um deles para 'Hora do Leste (EUA e Canadá)' (levando em consideração o horário de verão)? Algo como:

Annotation.last.created_at.in_eastern_time
Tom Lehman
fonte

Respostas:

191

Use o método in_time_zone da classe 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

Então, para o seu exemplo particular

Annotation.last.created_at.in_time_zone('Eastern Time (US & Canada)')
Steve Weet
fonte
7
ou você pode usar o identificador de horanow.in_time_zone(3)
fl00r
8
created_at.in_time_zone("EST")é mais curto
Orlando
51
"EST" = "Hora Padrão do Leste", então estará errado durante o Horário de Verão. "Hora do Leste (EUA e Canadá)" descobre se é horário de verão ou não para você.
jhiro009
1
Observe que o método in_time_zone é parte do ActiveSupport, portanto, é integrado ao Rails, mas não faz parte do stdlib do Ruby. Se você tem um aplicativo Rails, não tem problema. Se você tiver um aplicativo Ruby simples, precisará de suporte ativo.
Gayle
O link para a documentação deste método está aqui: apidock.com/rails/DateTime/in_time_zone
Naved Khan
17

Embora esta seja uma pergunta antiga, vale a pena mencionar algo. Em uma resposta anterior , é sugerido usar um before_filter para definir o fuso horário temporariamente.

Você nunca deve fazer isso porque o Time.zone armazena as informações no encadeamento e provavelmente vazará para a próxima solicitação tratada por esse encadeamento.

Em vez disso, você deve usar um around_filter para garantir que Time.zone seja redefinido após a conclusão da solicitação. Algo como:

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

Leia mais sobre isso aqui

Opsidao
fonte
1
Hoje em dia existe um bom método Time.use_zone .
freemanoid
9

Se você adicionar isso ao seu /config/application.rb

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

Então você pode usar o celular

Annotation.last.created_at.in_time_zone

para obter a hora no fuso horário especificado.

Eifion
fonte
se estivermos configurando o fuso horário em application.rb, não há necessidade de chamar ".in_time_zone". rails automaticamente fazem isso por nós, jyst precisa chamar Annotation.last.created_at
Vishal
3

Se você configurar seu /config/application.rb

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

Time.now.in_time_zone

DateTime.now.in_time_zone
Dorian
fonte
2

Defina seu fuso horário para o horário do leste.

Você pode definir o fuso horário padrão em config / environment.rb

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

Agora, todos os registros que você puxar estarão nesse fuso horário. Se você precisa de fusos horários diferentes, digamos com base em um fuso horário do usuário, você pode alterá-lo com um before_filter em seu controlador.

class ApplicationController < ActionController::Base

  before_filter :set_timezone

  def set_timezone
    Time.zone = current_user.time_zone
  end
end

Apenas certifique-se de armazenar todos os seus tempos no banco de dados como UTC e tudo ficará bem.

nitecoder
fonte
Isso importa se você está executando um servidor de aplicativos como mongrel, thin ou passageiro? Eles rodam mais de uma instância, single threaded eu acredito? Posso estar errado, adoraria saber!
nitecoder
4
Time.zone=é thread-safe github.com/rails/rails/blob/master/activesupport/lib/… .
para que não seja
Pode não ter sido em '09?
nitecoder de
2
@jpwynn: de acordo com isto: github.com/rails/rails/commit/… é Thread seguro há mais de 5 anos. Alguma fonte ou exemplo para o seu problema?
Pascal
1
Um thread pode servir a várias sessões. Se você definir uma vez quando o usuário estiver logado, por exemplo, o ÚLTIMO usuário a fazer logon irá definir o fuso horário para TODOS os usuários cuja sessão usa esse mesmo thread. Portanto, você DEVE usar um before_filter para defini-lo para cada usuário para cada carregamento de página.
jpw