30

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

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


或另一个例子:
"Pacific/Honolulu"=> 转换为 =>"Hawaii"

两者都在ActiveSupport::TimeZone < Object映射中可用,但 rails "Eastern Time (US & Canada)"在下拉、验证和存储到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

*使用设计和设计-不可避免


注册查看脚本

    <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 %>
4

2 回答 2

33

时间包含所需的逻辑,但要回答您的问题:

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

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

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

于 2013-01-08T23:55:15.197 回答
3

我相信每个人都真正追求的魔法,并解决了@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 显然正在重新审视时区支持以清理这项业务
于 2019-02-02T20:45:48.630 回答