Inicialmente pensei em adotar o horário de Brasília e colocar observações nos locais onde as datas e hora seriam exibidas, pois inicialmente o sistema teria um uso maior nas regiões que utilizam este fuso horário, além disso tornaria a implementação um pouco mais fácil.
Depois pensei em como eu gostaria que o sistema se comportasse se fosse eu o usuário, aí não restou dúvida, mesmo sabendo que o público alvo se concentraria mais em uma região, o serviço ainda continuará na nuvem, podendo ser acessado de todo o território nacional.
O Brasil possui 27 Unidades Federativas, sendo que apenas 9 utilizam o horário de Brasília, desta forma optar por utilizar apenas este fuso horário, seria ignorar 18 UFs!
Existem diversos posts a respeito de como utilizar o fuso horário do usuário que fez a requisição, um é o It's About Time (Zones) do pessoal da thoughtbot, que descreve até a inclusão do campo do fuso horário na edição do perfil do usuário.
A classe do Rails que contem os fusos horários é a ActiveSupport::TimeZone, porém o único fuso horário brasileiro é o de Brasília e eu gostaria de colocar todos os fusos horários, são apenas 4, nas primeiras opções do select.
A biblioteca TZInfo, utilizada pelo ActiveSupport::TimeZone, apresenta os seguintes fusos para o Brasil:
br = TZInfo::Country.get('BR')
br.zone_names
=> ["America/Noronha", "America/Belem", "America/Fortaleza", "America/Recife",
"America/Araguaina", "America/Maceio", "America/Bahia", "America/Sao_Paulo",
"America/Campo_Grande", "America/Cuiaba", "America/Santarem", "America/Porto_Velho",
"America/Boa_Vista", "America/Manaus", "America/Eirunepe", "America/Rio_Branco"]
Para adicionar os novos fusos, criei o arquivo config/initializers/active_support/time_zone.rb com o seguinte conteúdo:
ActiveSupport::TimeZone::MAPPING['Fernando de Noronha'] = 'America/Noronha'
ActiveSupport::TimeZone::MAPPING['Amazônia'] = 'America/Manaus'
ActiveSupport::TimeZone::MAPPING['Acre'] = 'America/Rio_Branco'
ActiveSupport::TimeZone.instance_variable_set('@zones', nil)
ActiveSupport::TimeZone.instance_variable_set('@zones_map', nil)
module ActiveSupport
class TimeZone
def self.br_zones
@br_zones ||= all.find_all { |z| z.name =~ /Brasilia|Noronha|Amazônia|Acre/ }
end
end
end
Fiz um mapeamento usando os nomes dos fusos horários que estão na Wikipédia, forcei as variávies @zones e @zones_map para nil, pois elas são cacheadas durante a criação do objeto que representa a classe ActiveSupport::TimeZone, desta forma quando clientes da classe fazem uso dos métodos all e/ou zone_maps (as únicas formas de acessá-las sem metaprogramação), estas variáveis são recomputadas.
Por último adicionei o método br_zones, inspirado no método us_zones, presente na classe, o que facilita a criação do select:
<%= f.input :time_zone, priority: ActiveSupport::TimeZone.br_zones %>