如何将 TZInfo 标识符转换为 Rails 时区名称/键
Posted
技术标签:
【中文标题】如何将 TZInfo 标识符转换为 Rails 时区名称/键【英文标题】:How to Convert TZInfo identifier to Rails TimeZone name/key 【发布时间】:2012-12-22 16:44:04 【问题描述】:如何将作为 TZInfo 标识符接收的 js 值转换为 Rails 时区名称/键?
FROM: "America/New_York"
从 JavaScript TZinfo 检测返回
收件人:"Eastern Time (US & Canada)"
Rails TimeZone 中使用的约定
或另一个例子:"Pacific/Honolulu"
=> 转换为 => "Hawaii"
两者都在ActiveSupport::TimeZone < Object
映射中可用,但rails 使用密钥[i.g. "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
User Time_Zone 实现如下: http://railscasts.com/episodes/106-time-zones-revised
*使用 Devise & Devise-Inevitable
注册查看脚本
<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 %>
【问题讨论】:
【参考方案1】:时间包含所需的逻辑,但要回答您的问题:
Time.zone = ActiveSupport::TimeZone.new("America/New_York")
编辑,我想我的答案不完整。你想从“美国/纽约”到“东部时间(美国和加拿大)”,对吗?如果是这种情况,这是我拥有的最佳解决方案——尽管有人可能会提供更好的解决方案。
ActiveSupport::TimeZone::MAPPING.select |k, v| v == "America/New_York" .keys.first
【讨论】:
也可以使用 .key 方法访问哈希,如下:ActiveSupport::TimeZone::MAPPING.key("America/New_York")
这不支持其他 TZinfo 名称,虽然像 "America/Vancouver"
这是一个比内置 ActiveSupport::TimeZone 更完整的映射:gist.github.com/jpmckinney/767070
@ifightcrime 的链接适用于大多数情况,但有些映射不正确,请参阅 github 页面底部的 cmets
官方 Ruby 映射在这里:github.com/rails/rails/blob/master/activesupport/lib/… 在我的例子中,我需要它用于使用 rails 后端的 javascript 应用程序,所以我需要列表而不是 ruby 函数。【参考方案2】:
我相信每个人都真正追求的魔力,并解决了@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 不会为您提供偏移量,除非您在感兴趣的区域中创建 TZInfo::TimezonePeriod Ruby 2.6 显然正在重新审视时区支持以清理这项业务【讨论】:
这样更好,但并不总是准确的。America/St_Thomas
(全年大西洋标准时间)映射到 Atlantic Time (Canada)
,它遵守 DST。它需要改为Puerto Rico
。以上是关于如何将 TZInfo 标识符转换为 Rails 时区名称/键的主要内容,如果未能解决你的问题,请参考以下文章
python - 如何在Python中转换为UTC后完全删除tzinfo?
如何实现“tzinfo”以将当前 GMT 偏移到 EST(GMT -4:00)?