如何将TZInfo标识符转换为Rails TimeZone名称/密钥

时间:2013-01-08 18:26:18

标签: ruby-on-rails ruby-on-rails-3 timezone activesupport tzinfo

如何将收到的作为TZInfo标识符的js值转换为Rails TimeZone名称/密钥?

从JavaScript TZinfo检测返回的FROM:"America/New_York" 在Rails TimeZone中使用的 TO:"Eastern Time (US & Canada)"约定


或其他例子:
"Pacific/Honolulu" =>转换为=> "Hawaii"

两者都在ActiveSupport::TimeZone < Object映射中可用,但rails使用密钥[i.g. "Eastern Time (US & Canada)"]在下拉列表,验证和&amp;存储到Time.use_zone()


基于我对ActiveSupport::TimeZone.us_zones的理解,这似乎很重要,尤其是DayLights节省时间(轨道声音可以很好地处理),并且只能匹配偏移量。如果未使用rails TimeZone名称存储到DB,则验证将失败,并且在用户的配置文件设置页面中无法正确匹配,并且下拉列表为ActiveSupport::TimeZone.zones_map

目标是用户无需在注册时选择他们的时区,或者在注册后需要在其设置中更改时区。浏览器检测到它并在注册时将其传递给hidden_​​field。在极少数情况下,他们在与家庭/工作不同的地方注册。他们可以稍后在其帐户设置中手动覆盖。

在尝试摄取js时区检测时似乎是一个常见的差距。这甚至可能成为如何将返回的信息从js传递给rails进行转换然后返回js以存储回表单的hidden_​​field的次要问题?希望我能正确地解决这个问题。不可否认的是有轨道的绿色,所以可能有一个简单的解决方案......

非常感谢所有的帮助!
-E


ActiveSupport Time.zone文档
http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#method-i-parse

MAPPING = {"Eastern Time (US & Canada)" => "America/New_York"


使用js打包gem'temporal-rails'来检测用户时区:
https://github.com/jejacks0n/temporal

用户Time_Zone实现如下所示:
http://railscasts.com/episodes/106-time-zones-revised

*使用Devise&amp;设计-必然


注册视图脚本

    <script>
    $(function() {
        var detected_zone = Temporal.detect();
        console.log(detected_zone);  // returns object
        detected_zone = detected_zone.timezone.name;
        console.log(detected_zone);  // returns "America/New_York"
        $('#user_time_zone').val(detected_zone);  // ! need to convert this to rails TimeZone name !
    });
    </script>

用户模型

    validates_inclusion_of :time_zone, in: ActiveSupport::TimeZone.zones_map(&:name)

用户帐户设置表单

    <%= f.label :time_zone, label: "Time Zone" %><br />
    <%= f.time_zone_select :time_zone, ActiveSupport::TimeZone.us_zones %>

2 个答案:

答案 0 :(得分:23)

时间包括所需的逻辑,但回答你的问题:

Time.zone = ActiveSupport::TimeZone.new("America/New_York")

编辑,我想我的答案是不完整的。你想把它从“America / New_York”带到“东部时间(美国和加拿大)”,对吗?如果是这种情况,这是我的最佳解决方案 - 尽管有人可能能够提供更好的解决方案。

ActiveSupport::TimeZone::MAPPING.select {|k, v| v == "America/New_York" }.keys.first

答案 1 :(得分:1)

在魔术相信大家是真的后,解决了@ajbraus提出的问题,是一个班轮这可能是的奇怪的最难的事情之一找到任何地方讨论:

timezone = ActiveSupport::TimeZone[TZInfo::Timezone.get('America/Vancouver').period_for_utc(Time.now.utc).utc_offset]
 => #<ActiveSupport::TimeZone:0x00007fc2baa6d900 @name="Pacific Time (US & Canada)", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: America/Los_Angeles>> 

否则,如果您尝试搜索ActiveSupport的整个区域数据库,则会得到nada:

ActiveSupport::TimeZone.all.find{ |tz| tz.tzinfo == ActiveSupport::TimeZone.find_tzinfo('America/Vancouver') }
 => nil

在复杂性归结为如下:

  • TZInfo gem严格遵守IANA时区规范
  • Rails的ActiveSupport决定尝试简化区域的显示/使用,但不是区域的详尽数据库
  • 的ActiveSupport可以查找合适的区域,如果你给它一个偏移量
  • 除非您在感兴趣的区域中创建TZInfo :: TimezonePeriod,否则TZInfo不会给您偏移量
  • Ruby 2.6显然正在重新访问时区支持以清理这项业务