Ruby On Rails: usando a string do ActiveSupport TimeZone salva pelo usuário para disparar um trabalho à meia-noite do usuário

Portanto, você permitiu que seus usuários armazenassem seus fusos horários no banco de dados para que pudesse fazer alguma mágica para eles em algum momento no futuro. Seu formulário pode ser parecido com este:

<%= form_for @object do |f| %>  
<div class="col-xs-12 field">
<%= f.label :time_zone, 'Time Zone:', :class => "col-xs-3" %>
<%= f.time_zone_select( :time_zone, nil, include_blank: true, :class => "col-xs-8") %>
</div>
<div class="col-xs-12 actions">
<%= f.submit "Save Changes" %>
</div>
<% end %>

Agora você deseja executar um trabalho à meia-noite todas as noites quando chega o dia, mas precisa fazê-lo especificamente à meia-noite do usuário e não no UTC (o fuso horário padrão do Rails). Estando na bola, você reconhece que tudo tem que ser relativo ao primeiro lugar na terra (de acordo com o ActiveSupport de qualquer maneira) para trazer o novo dia, nomeadamente as Ilhas Tokelau. Seu trabalho pode conter um código parecido com este:

def AwesomeJobName(object)
today
= DateTime.now.in_time_zone("Tokelau Is.").to_date
if DateTime.now.in_time_zone(object.time_zone).to_date == today
do_amazing_magical_thing_that_will_win_your_users_eternal_love_here

end
end

Então o que aconteceu? Primeiro pegamos a data em UTC +13. Esta é a data de referência. Está no futuro para quase todos os lugares da terra, então você sabe se hoje ainda há amanhã onde você está, a meia-noite ainda não chegou. Quando chegar, seu cron job de hora em hora que você configurou em outro lugar (um tópico além do escopo desta postagem) passará repentinamente pela instrução if e a lógica incluída será acionada. Você provavelmente desejará definir algumas outras condições na instrução if para garantir que a hora seja meia-noite, para certificar-se de que ele dispara apenas uma vez à meia-noite e não a cada hora daquele dia até que a instrução if não passe novamente. No meu caso, eu estava usando o trabalho para atualizar um campo de status no banco de dados de pendente para ativo, de modo que só dispararia se o status ainda não tivesse sido atualizado, o que só poderia acontecer uma vez.

A mágica acima tem a ver com o in_time_zone(<insert ActiveSupport::Timezone string here>)método. O time_zone_selectassistente de formulário no topo preenche automaticamente uma caixa de seleção que você usa para gravar uma string ActiveSupport :: Timezone no banco de dados. Você pode colocar essa string DateTime.now.in_time_zone()e ela cuspirá o DateTime atual correto para o seu usuário. Experimente no console com, DateTime.now.in_time_zone("Berlin")por exemplo. Ele deve retornar um resultado semelhante a Fri, 01 Apr 2016 21:36:26 CEST +02:00. Isso torna o trabalho e o cálculo entre fusos horários no Rails realmente simples e economiza muito tempo. Não se preocupe com TZInfo ou qualquer outro feitiço confuso de fuso horário.