Converter UTC para hora local no Rails 3

95

Estou tendo problemas para converter um UTC Timeou TimeWithZonepara a hora local no Rails 3.

Digamos que momentseja alguma Timevariável em UTC (por exemplo moment = Time.now.utc). Como faço momentpara converter para meu fuso horário, cuidando do DST (ou seja, usando EST / EDT)?

Mais precisamente, gostaria de imprimir "Segunda-feira, 14 de março, 9h" se a hora corresponder a esta manhã, 9h EDT, e "Segunda-feira, 7 de março, 9h", se a hora for 9h EST na última segunda-feira.

Esperançosamente, há outra maneira?

Edit : Primeiro pensei que "EDT" deveria ser um fuso horário reconhecido, mas "EDT" não é um fuso horário real, mais como o estado de um fuso horário. Por exemplo, não faria sentido pedir Time.utc(2011,1,1).in_time_zone("EDT"). É um pouco confuso, pois "EST" é um fuso horário real, usado em alguns lugares que não usam o horário de verão e duram (UTC-5) um ano.

Marc-André Lafortune
fonte

Respostas:

113

Rails tem seus próprios nomes. Veja-os com:

rake time:zones:us

Você também pode correr rake time:zones:allpara todos os fusos horários. Para ver mais tarefas de rake relacionadas à zona:rake -D time

Portanto, para converter para EST, fornecendo o horário de verão automaticamente:

Time.now.in_time_zone("Eastern Time (US & Canada)")
Zabba
fonte
21
Como você poderia usar automaticamente o fuso horário para o usuário que acessa o aplicativo da web?
dmonopólio de
A única maneira que encontrei foi com Javascript e depois repassando para o servidor. (new Date()).getTimeZoneOffset(). Mas é bastante inconsistente, então esse cara parece ter escrito o seu próprio: onlineaspect.com/2007/06/08/…
Duque
2
adicionar automaticamente o fuso horário a todos os horários de ActiveRecord - config.time_zone = 'Hora do Leste (EUA e Canadá)' - em config / application.rb
idrinkpabst
Atualização: o proprietário da solução JS vinculada aponta para a solução mais recente: pellepim.bitbucket.org/jstz
Miles
@dmonopoly você pode definir o fuso horário na configuração do aplicativo config.time_zone = 'Wellington'e, em seguida, usar Time.current (que é equivalente a time.now, mas usou o fuso horário que você definiu)
Sean
114

Time#localtime fornecerá a hora no fuso horário atual da máquina que está executando o código:

> moment = Time.now.utc
  => 2011-03-14 15:15:58 UTC 
> moment.localtime
  => 2011-03-14 08:15:58 -0700 

Atualização: Se você deseja converter para fusos horários específicos, em vez de seu próprio fuso horário, você está no caminho certo. No entanto, em vez de se preocupar com EST vs EDT, passe apenas pelo fuso horário do Leste - ele saberá com base no dia se é EDT ou EST:

> Time.now.utc.in_time_zone("Eastern Time (US & Canada)")
  => Mon, 14 Mar 2011 11:21:05 EDT -04:00 
> (Time.now.utc + 10.months).in_time_zone("Eastern Time (US & Canada)")
  => Sat, 14 Jan 2012 10:21:18 EST -05:00 
Dylan Markow
fonte
Isso é um começo. Como posso definir o fuso horário atual (já que nem tenho certeza de onde o aplicativo será hospedado, o servidor pode estar em um fuso horário diferente do que deveria ser usado).
Marc-André Lafortune
6
O método "localtime" é legal, mas o fuso horário da máquina que executa o código não é tão útil quanto o fuso horário do usuário acessando o aplicativo da web. (Conforme mencionado aqui: stackoverflow.com/questions/6003491/rails-3-user-timezones/… ) Como você poderia obter o fuso horário do usuário que acessa o aplicativo da web?
dmonopólio de
@daze Imagino que você possa configurar uma opção para seus usuários escolherem seus fusos horários e, em seguida, usar o in_time_zonemétodo com seus fusos horários.
Dylan Markow de
1
Obrigado, o método localtime é exatamente o que eu precisava.
Bob
Time.now.localtimefunciona em uma sessão normal de irb, mas quando tento executá-lo em uma máquina que está no fuso horário UTC, ele não funciona.
Ava
15

É fácil configurá-lo usando a zona local do sistema, apenas em seu application.rb adicione isso

config.time_zone = Time.now.zone

Então, o rails deve mostrar carimbos de data / hora em seu horário local ou você pode usar algo como esta instrução para obter o horário local

Post.created_at.localtime
jacr1614
fonte
15

Na verdade, existe um bom Gem chamado local_timepelo basecamp para fazer tudo isso apenas no lado do cliente, eu acredito:

https://github.com/basecamp/local_time

Mahatmanich
fonte
Isso funciona melhor. Já sabemos o tempo armazenado, a maneira de mostrá-lo no formato para o usuário é melhor feito no lado do cliente na minha opinião e é só isso.
Neeraj Shukla
1

Não sei por que, mas no meu caso não funciona da maneira sugerida anteriormente. Mas funciona assim:

Time.now.change(offset: "-3000")

Claro que você precisa mudar o offsetvalor para o seu.

Seybo Glaux
fonte
0

Se você está realmente fazendo isso só porque deseja obter o fuso horário do usuário, tudo o que você precisa fazer é alterá-lo config/applications.rb.

Como isso:

Rails, por padrão, salvará seu registro de tempo em UTC mesmo se você especificar o fuso horário atual.

config.time_zone = "Singapore"

Portanto, isso é tudo que você precisa fazer e está pronto para continuar.

há realadreinamento
fonte