将 Microsoft 时区转换为 rails 中的标准时区数据
Converting Microsoft Timezone to standards timezone data in rails
我有一个连接到 SQL 服务器数据库的 rails 应用程序,还有一个连接到同一数据库的 windows 桌面应用程序。 Windows 应用程序正在使用 Microsoft windows 时区数据库,因此我得到了一个像 Pacific Daylight Time
这样的时区名称。在 rails 中,ActiveSupport::TimeZone
class 为我们提供了一个映射散列,其中键类似于 Pacific Time (US & Canada)
,值类似于 America/Los_Angeles
。是否已经有任何东西可以将 windows 格式转换为标准格式以便我可以使用 Time.zone
?
或者是否有一个时区 gem 允许我配置 rails 以使用 windows 格式?
这是我已经开始帮助转换的数组,但有一点我不是 100% 确定。
DAYLIGHT = [
{name: 'Dateline Daylight Time', offset: -12, alt: 'International Date Line West'},
{name: 'UTC-11', offset: -11, alt: ''},
{name: 'Hawaiian Daylight Time', offset: -10, alt: 'Hawaii'},
{name: 'Alaskan Daylight Time', offset: -9, alt: 'Alaska'},
{name: 'Pacific Daylight Time (Mexico)', offset: -8, alt: ''},
{name: 'Pacific Daylight Time', offset: -8, alt: 'Pacific Time (US & Canada)'},
{name: 'US Mountain Daylight Time', offset: -7, alt: 'Mountain Time (US & Canada)'},
{name: 'Mountain Daylight Time (Mexico)', offset: -7, alt: ''},
{name: 'Mountain Daylight Time', offset: -7, alt: 'Mountain Time (US & Canada)'},
{name: 'Central America Daylight Time', offset: -6, alt: 'Central Time (US & Canada)'},
{name: 'Central Daylight Time', offset: -6, alt: 'Central Time (US & Canada)'},
{name: 'Central Daylight Time (Mexico)', offset: -6, alt: ''},
{name: 'Canada Central Daylight Time', offset: -6, alt: ''},
{name: 'SA Pacific Daylight Time', offset: -5, alt: ''},
{name: 'Eastern Daylight Time', offset: -5, alt: 'Eastern Time (US & Canada)'},
{name: 'US Eastern Daylight Time', offset: -5, alt: 'Eastern Time (US & Canada)'},
{name: 'Venezuela Daylight Time', offset: -4.5, alt: ''},
{name: 'Paraguay Daylight Time', offset: -4, alt: ''},
{name: 'Atlantic Daylight Time', offset: -4, alt: ''},
{name: 'Central Brazilian Daylight Time', offset: -4, alt: ''},
{name: 'SA Western Daylight Time', offset: -4, alt: ''},
{name: 'Pacific SA Daylight Time', offset: -4, alt: ''},
{name: 'Newfoundland Daylight Time', offset: -3.5, alt: ''},
{name: 'E. South America Daylight Time', offset: -3, alt: ''},
{name: 'Argentina Daylight Time', offset: -3, alt: ''},
{name: 'SA Eastern Daylight Time', offset: -3, alt: ''},
{name: 'Greenland Daylight Time', offset: -3, alt: ''},
{name: 'Montevideo Daylight Time', offset: -3, alt: ''},
{name: 'Bahia Daylight Time', offset: -3, alt: ''},
{name: 'UTC-02', offset: -2, alt: ''},
{name: 'Mid-Atlantic Daylight Time', offset: -2, alt: ''},
{name: 'Azores Daylight Time', offset: -1, alt: ''},
{name: 'Cabo Verde Daylight Time', offset: -1, alt: ''},
{name: 'Morocco Daylight Time', offset: 0, alt: ''},
{name: 'Coordinated Universal Time', offset: 0, alt: ''},
{name: 'GMT Daylight Time', offset: 0, alt: ''},
{name: 'Greenwich Daylight Time', offset: 0, alt: ''},
{name: 'W. Europe Daylight Time', offset: 1, alt: ''},
{name: 'Central Europe Daylight Time', offset: 1, alt: ''},
{name: 'Romance Daylight Time', offset: 1, alt: ''},
{name: 'Central European Daylight Time', offset: 1, alt: ''},
{name: 'W. Central Africa Daylight Time', offset: 1, alt: ''},
{name: 'Namibia Daylight Time', offset: 1, alt: ''},
{name: 'Jordan Daylight Time', offset: 2, alt: ''},
{name: 'GTB Daylight Time', offset: 2, alt: ''},
{name: 'Middle East Daylight Time', offset: 2, alt: ''},
{name: 'Egypt Daylight Time', offset: 2, alt: ''},
{name: 'Syria Daylight Time', offset: 2, alt: ''},
{name: 'E. Europe Daylight Time', offset: 2, alt: ''},
{name: 'South Africa Daylight Time', offset: 2, alt: ''},
{name: 'FLE Daylight Time', offset: 2, alt: ''},
{name: 'Turkey Daylight Time', offset: 2, alt: ''},
{name: 'Jerusalem Daylight Time', offset: 2, alt: ''},
{name: 'Russia TZ 1 Daylight Time', offset: 2, alt: ''},
{name: 'Libya Daylight Time', offset: 2, alt: ''},
{name: 'Arabic Daylight Time', offset: 3, alt: ''},
{name: 'Arab Daylight Time', offset: 3, alt: ''},
{name: 'Belarus Daylight Time', offset: 3, alt: ''},
{name: 'Russia TZ 2 Daylight Time', offset: 3, alt: ''},
{name: 'E. Africa Daylight Time', offset: 3, alt: ''},
{name: 'Iran Daylight Time', offset: 3.5, alt: ''},
{name: 'Arabian Daylight Time', offset: 4, alt: ''},
{name: 'Azerbaijan Daylight Time', offset: 4, alt: ''},
{name: 'Russia TZ 3 Daylight Time', offset: 4, alt: ''},
{name: 'Mauritius Daylight Time', offset: 4, alt: ''},
{name: 'Georgian Daylight Time', offset: 4, alt: ''},
{name: 'Caucasus Daylight Time', offset: 4, alt: ''},
{name: 'Afghanistan Daylight Time', offset: 4.5, alt: ''},
{name: 'West Asia Daylight Time', offset: 5, alt: ''},
{name: 'Russia TZ 4 Daylight Time', offset: 5, alt: ''},
{name: 'Pakistan Daylight Time', offset: 5, alt: ''},
{name: 'India Daylight Time', offset: 5.5, alt: ''},
{name: 'Sri Lanka Daylight Time', offset: 5.5, alt: ''},
{name: 'Nepal Daylight Time', offset: 5.75, alt: ''},
{name: 'Central Asia Daylight Time', offset: 6, alt: ''},
{name: 'Bangladesh Daylight Time', offset: 6, alt: ''},
{name: 'Russia TZ 5 Daylight Time', offset: 6, alt: ''},
{name: 'Myanmar Daylight Time', offset: 6.5, alt: ''},
{name: 'SE Asia Daylight Time', offset: 7, alt: ''},
{name: 'Russia TZ 6 Daylight Time', offset: 7, alt: ''},
{name: 'China Daylight Time', offset: 8, alt: ''},
{name: 'Russia TZ 7 Daylight Time', offset: 8, alt: ''},
{name: 'Malay Peninsula Daylight Time', offset: 8, alt: ''},
{name: 'W. Australia Daylight Time', offset: 8, alt: ''},
{name: 'Taipei Daylight Time', offset: 8, alt: ''},
{name: 'Ulaanbaatar Daylight Time', offset: 8, alt: ''},
{name: 'Tokyo Daylight Time', offset: 9, alt: ''},
{name: 'Korea Daylight Time', offset: 9, alt: ''},
{name: 'Russia TZ 8 Daylight Time', offset: 9, alt: ''},
{name: 'Cen. Australia Daylight Time', offset: 9.5, alt: ''},
{name: 'AUS Central Daylight Time', offset: 9.5, alt: ''},
{name: 'E. Australia Daylight Time', offset: 10, alt: ''},
{name: 'AUS Eastern Daylight Time', offset: 10, alt: ''},
{name: 'West Pacific Daylight Time', offset: 10, alt: ''},
{name: 'Tasmania Daylight Time', offset: 10, alt: ''},
{name: 'Magadan Daylight Time', offset: 10, alt: ''},
{name: 'Russia TZ 9 Daylight Time', offset: 10, alt: ''},
{name: 'Russia TZ 10 Daylight Time', offset: 11, alt: ''},
{name: 'Central Pacific Daylight Time', offset: 11, alt: ''},
{name: 'Russia TZ 11 Daylight Time', offset: 12, alt: ''},
{name: 'New Zealand Daylight Time', offset: 12, alt: ''},
{name: 'UTC+12', offset: 12, alt: ''},
{name: 'Fiji Daylight Time', offset: 12, alt: ''},
{name: 'Kamchatka Daylight Time', offset: 12, alt: ''},
{name: 'Tonga Daylight Time', offset: 13, alt: ''},
{name: 'Samoa Daylight Time', offset: 13, alt: ''},
{name: 'Line Islands Daylight Time', offset: 14, alt: ''}
]
改进答案
我的原始答案(下方)中描述的功能现在可以在我的 TimeZoneConverter .NET 库中使用。所有艰苦的工作都为您完成,并随着世界时区的变化而不断更新。项目自述文件中的示例展示了如何在 Windows、IANA 和 Rails 标识符之间进行转换。
由于问题中描述的应用程序在 Rails 中,我建议 运行 在 .NET 中进行后台作业,将 Windows 时区 ID 转换为 Rails 应用并将它们放在单独的列中。
原答案
您要查找的资源是作为 Unicode CLDR project. The file is located within the CLDR release at common/supplemental/windowsZones.xml
, and you can find the current "development version" of it here.
的一部分维护的 Windows 到 IANA 映射文件
注意几点:
文件 会随着 Microsoft 和 IANA 的新时区更新,或者偶尔当政府大幅更改时区规则以致应用不同的映射。
您列表中的偏移量只是 标准 偏移量 - 即在夏令时无效时应用的偏移量。 “时区”由标准偏移量、夏令时偏移量、DST 转换的特定日期和时间以及偏移量和转换的更改历史组成。
不应在 Rails 以外的任何地方使用 Rails 时区名称。我的理解是,它们实际上是在 Rails 决定使用标准 IANA/Olson 时区之前创建的,然后在 Ruby tzinfo gem became viable, the Rails zones were retrofitted through the MAPPING
constant shown on this page ,然后随着个人投诉的出现而添加了一些。如果可能,通过 tzinfo gem 直接使用 IANA 时区。如果没有,那么您将需要经过两层映射(Microsoft -> IANA -> Rails)。
我不知道 CLDR 映射的 Rails 特定实现。我检查了 Rails 项目的几个 CLDR,发现它们不包括 CLDR 的特定部分。但是,如果您可以控制 Windows 方面的事情,那么您可以考虑使用我描述的 in this answer 的 .NET 实现。您可以在 Windows 端进行 Windows 到 IANA 的转换,然后直接将 IANA 区域与 tzinfo 一起使用,或者映射到 Rails 应用中的 Rails 区域。
也意识到 Rails 时区的数量明显少于 IANA 支持的数量。我没有检查过,但很可能某些 Windows 区域映射到不在 Rails 中的 IANA 区域。此外,有些 Rails 区域有多个 Rails 条目,但只有一个 IANA 映射 - 本质上使它们成为等效别名。
Rails和Windows都使用“UTC”作为区域id,Rails映射到“Etc/UTC”,但是CLDR映射到“Etc/GMT”。你必须手动处理这个。
最后,认识到 CLDR 使用“稳定”标识符的方式与 IANA 的“规范”标识符不同,这可能会在映射过程中造成一些困难。
例如,考虑 Microsoft 区域“印度标准时间”映射到 CLDR 中的“Asia/Calcutta”,因为那是 原始 IANA 区域是。但是,IANA 将区域更改为“Asia/Kolkata”,并为“Asia/Calcutta”设置了 link 以向后兼容。当您查看 Rails MAPPING
常量时,有四个 Rails 区域,“Chennai”、“Kolkata”、“Mumbai”和“New Delhi”——所有这些区域都已映射到“Asia/Kolkata”。
为了克服这个问题,您将还 需要来自 CLDR 的另一个文件,common/bcp47/timezone.xml
。您可以使用此文件查找别名 IANA 区域之间的所有 link,这可以帮助您映射回 Rails 区域。
所以是的,这是可能的 - 但这并不容易。 ;)
我已经为你做了当前映射,如下:
"Windows","IANA","Rails"
"W. Central Africa Standard Time","Africa/Algiers","West Central Africa"
"Egypt Standard Time","Africa/Cairo","Cairo"
"Morocco Standard Time","Africa/Casablanca","Casablanca"
"South Africa Standard Time","Africa/Harare","Harare"
"South Africa Standard Time","Africa/Johannesburg","Pretoria"
"Greenwich Standard Time","Africa/Monrovia","Monrovia"
"E. Africa Standard Time","Africa/Nairobi","Nairobi"
"Argentina Standard Time","America/Argentina/Buenos_Aires","Buenos Aires"
"SA Pacific Standard Time","America/Bogota","Bogota"
"Venezuela Standard Time","America/Caracas","Caracas"
"Central Standard Time","America/Chicago","Central Time (US & Canada)"
"Mountain Standard Time (Mexico)","America/Chihuahua","Chihuahua"
"Mountain Standard Time","America/Denver","Mountain Time (US & Canada)"
"Greenland Standard Time","America/Godthab","Greenland"
"Central America Standard Time","America/Guatemala","Central America"
"SA Western Standard Time","America/Guyana","Georgetown"
"Atlantic Standard Time","America/Halifax","Atlantic Time (Canada)"
"US Eastern Standard Time","America/Indiana/Indianapolis","Indiana (East)"
"Alaskan Standard Time","America/Juneau","Alaska"
"SA Western Standard Time","America/La_Paz","La Paz"
"SA Pacific Standard Time","America/Lima","Lima"
"SA Pacific Standard Time","America/Lima","Quito"
"Pacific Standard Time","America/Los_Angeles","Pacific Time (US & Canada)"
"Mountain Standard Time (Mexico)","America/Mazatlan","Mazatlan"
"Central Standard Time (Mexico)","America/Mexico_City","Guadalajara"
"Central Standard Time (Mexico)","America/Mexico_City","Mexico City"
"Central Standard Time (Mexico)","America/Monterrey","Monterrey"
"Montevideo Standard Time","America/Montevideo","Montevideo"
"Eastern Standard Time","America/New_York","Eastern Time (US & Canada)"
"US Mountain Standard Time","America/Phoenix","Arizona"
"Canada Central Standard Time","America/Regina","Saskatchewan"
"Pacific SA Standard Time","America/Santiago","Santiago"
"E. South America Standard Time","America/Sao_Paulo","Brasilia"
"Newfoundland Standard Time","America/St_Johns","Newfoundland"
"Pacific Standard Time","America/Tijuana","Tijuana"
"Central Asia Standard Time","Asia/Almaty","Almaty"
"Arabic Standard Time","Asia/Baghdad","Baghdad"
"Azerbaijan Standard Time","Asia/Baku","Baku"
"SE Asia Standard Time","Asia/Bangkok","Bangkok"
"SE Asia Standard Time","Asia/Bangkok","Hanoi"
"China Standard Time","Asia/Chongqing","Chongqing"
"Sri Lanka Standard Time","Asia/Colombo","Sri Jayawardenepura"
"Bangladesh Standard Time","Asia/Dhaka","Astana"
"Bangladesh Standard Time","Asia/Dhaka","Dhaka"
"China Standard Time","Asia/Hong_Kong","Hong Kong"
"North Asia East Standard Time","Asia/Irkutsk","Irkutsk"
"SE Asia Standard Time","Asia/Jakarta","Jakarta"
"Israel Standard Time","Asia/Jerusalem","Jerusalem"
"Afghanistan Standard Time","Asia/Kabul","Kabul"
"Russia Time Zone 11","Asia/Kamchatka","Kamchatka"
"Pakistan Standard Time","Asia/Karachi","Islamabad"
"Pakistan Standard Time","Asia/Karachi","Karachi"
"Nepal Standard Time","Asia/Kathmandu","Kathmandu"
"India Standard Time","Asia/Kolkata","Chennai"
"India Standard Time","Asia/Kolkata","Kolkata"
"India Standard Time","Asia/Kolkata","Mumbai"
"India Standard Time","Asia/Kolkata","New Delhi"
"North Asia Standard Time","Asia/Krasnoyarsk","Krasnoyarsk"
"Singapore Standard Time","Asia/Kuala_Lumpur","Kuala Lumpur"
"Arab Standard Time","Asia/Kuwait","Kuwait"
"Magadan Standard Time","Asia/Magadan","Magadan"
"Arabian Standard Time","Asia/Muscat","Abu Dhabi"
"Arabian Standard Time","Asia/Muscat","Muscat"
"N. Central Asia Standard Time","Asia/Novosibirsk","Novosibirsk"
"Myanmar Standard Time","Asia/Rangoon","Rangoon"
"Arab Standard Time","Asia/Riyadh","Riyadh"
"Korea Standard Time","Asia/Seoul","Seoul"
"China Standard Time","Asia/Shanghai","Beijing"
"Singapore Standard Time","Asia/Singapore","Singapore"
"Russia Time Zone 10","Asia/Srednekolymsk","Srednekolymsk"
"Taipei Standard Time","Asia/Taipei","Taipei"
"West Asia Standard Time","Asia/Tashkent","Tashkent"
"Georgian Standard Time","Asia/Tbilisi","Tbilisi"
"Iran Standard Time","Asia/Tehran","Tehran"
"Tokyo Standard Time","Asia/Tokyo","Osaka"
"Tokyo Standard Time","Asia/Tokyo","Sapporo"
"Tokyo Standard Time","Asia/Tokyo","Tokyo"
"Ulaanbaatar Standard Time","Asia/Ulaanbaatar","Ulaanbaatar"
"Central Asia Standard Time","Asia/Urumqi","Urumqi"
"Vladivostok Standard Time","Asia/Vladivostok","Vladivostok"
"Yakutsk Standard Time","Asia/Yakutsk","Yakutsk"
"Ekaterinburg Standard Time","Asia/Yekaterinburg","Ekaterinburg"
"Caucasus Standard Time","Asia/Yerevan","Yerevan"
"Azores Standard Time","Atlantic/Azores","Azores"
"Cape Verde Standard Time","Atlantic/Cape_Verde","Cape Verde Is."
"UTC-02","Atlantic/South_Georgia","Mid-Atlantic"
"Cen. Australia Standard Time","Australia/Adelaide","Adelaide"
"E. Australia Standard Time","Australia/Brisbane","Brisbane"
"AUS Central Standard Time","Australia/Darwin","Darwin"
"Tasmania Standard Time","Australia/Hobart","Hobart"
"AUS Eastern Standard Time","Australia/Melbourne","Canberra"
"AUS Eastern Standard Time","Australia/Melbourne","Melbourne"
"W. Australia Standard Time","Australia/Perth","Perth"
"AUS Eastern Standard Time","Australia/Sydney","Sydney"
"UTC","Etc/UTC","UTC"
"W. Europe Standard Time","Europe/Amsterdam","Amsterdam"
"GTB Standard Time","Europe/Athens","Athens"
"Central Europe Standard Time","Europe/Belgrade","Belgrade"
"W. Europe Standard Time","Europe/Berlin","Berlin"
"W. Europe Standard Time","Europe/Berlin","Bern"
"Central Europe Standard Time","Europe/Bratislava","Bratislava"
"Romance Standard Time","Europe/Brussels","Brussels"
"GTB Standard Time","Europe/Bucharest","Bucharest"
"Central Europe Standard Time","Europe/Budapest","Budapest"
"Romance Standard Time","Europe/Copenhagen","Copenhagen"
"GMT Standard Time","Europe/Dublin","Dublin"
"FLE Standard Time","Europe/Helsinki","Helsinki"
"Turkey Standard Time","Europe/Istanbul","Istanbul"
"Kaliningrad Standard Time","Europe/Kaliningrad","Kaliningrad"
"FLE Standard Time","Europe/Kiev","Kyiv"
"GMT Standard Time","Europe/Lisbon","Lisbon"
"Central Europe Standard Time","Europe/Ljubljana","Ljubljana"
"GMT Standard Time","Europe/London","Edinburgh"
"GMT Standard Time","Europe/London","London"
"Romance Standard Time","Europe/Madrid","Madrid"
"Belarus Standard Time","Europe/Minsk","Minsk"
"Russian Standard Time","Europe/Moscow","Moscow"
"Russian Standard Time","Europe/Moscow","St. Petersburg"
"Romance Standard Time","Europe/Paris","Paris"
"Central Europe Standard Time","Europe/Prague","Prague"
"FLE Standard Time","Europe/Riga","Riga"
"W. Europe Standard Time","Europe/Rome","Rome"
"Russia Time Zone 3","Europe/Samara","Samara"
"Central European Standard Time","Europe/Sarajevo","Sarajevo"
"Central European Standard Time","Europe/Skopje","Skopje"
"FLE Standard Time","Europe/Sofia","Sofia"
"W. Europe Standard Time","Europe/Stockholm","Stockholm"
"FLE Standard Time","Europe/Tallinn","Tallinn"
"W. Europe Standard Time","Europe/Vienna","Vienna"
"FLE Standard Time","Europe/Vilnius","Vilnius"
"Russian Standard Time","Europe/Volgograd","Volgograd"
"Central European Standard Time","Europe/Warsaw","Warsaw"
"Central European Standard Time","Europe/Zagreb","Zagreb"
"Samoa Standard Time","Pacific/Apia","Samoa"
"New Zealand Standard Time","Pacific/Auckland","Auckland"
"New Zealand Standard Time","Pacific/Auckland","Wellington"
"Tonga Standard Time","Pacific/Fakaofo","Tokelau Is."
"Fiji Standard Time","Pacific/Fiji","Fiji"
"Central Pacific Standard Time","Pacific/Guadalcanal","Solomon Is."
"West Pacific Standard Time","Pacific/Guam","Guam"
"Hawaiian Standard Time","Pacific/Honolulu","Hawaii"
"UTC+12","Pacific/Majuro","Marshall Is."
"UTC-11","Pacific/Midway","International Date Line West"
"UTC-11","Pacific/Midway","Midway Island"
"Central Pacific Standard Time","Pacific/Noumea","New Caledonia"
"UTC-11","Pacific/Pago_Pago","American Samoa"
"West Pacific Standard Time","Pacific/Port_Moresby","Port Moresby"
"Tonga Standard Time","Pacific/Tongatapu","Nuku'alofa"
请注意,上面的列表包括多个 Rails 区域映射回同一 Windows 区域的条目。在 Windows 到 Rails 方向映射时,您可能只想选择其中之一。
此外,上面的列表不包括无法映射的区域,如下(CSV):
"Windows","IANA","Rails"
"","Pacific/Chatham","Chatham Is."
"Dateline Standard Time","Etc/GMT+12",""
"Pacific Standard Time (Mexico)","America/Santa_Isabel",""
"Eastern Standard Time (Mexico)","America/Cancun",""
"Paraguay Standard Time","America/Asuncion",""
"Central Brazilian Standard Time","America/Cuiaba",""
"SA Eastern Standard Time","America/Cayenne",""
"Bahia Standard Time","America/Bahia",""
"Namibia Standard Time","Africa/Windhoek",""
"Jordan Standard Time","Asia/Amman",""
"Middle East Standard Time","Asia/Beirut",""
"Syria Standard Time","Asia/Damascus",""
"E. Europe Standard Time","Etc/GMT-2",""
"Libya Standard Time","Africa/Tripoli",""
"Mauritius Standard Time","Indian/Mauritius",""
"Line Islands Standard Time","Pacific/Kiritimati",""
感谢@MattJohnson-Pint,经过很长时间的研究,我能够解决这个问题,但是我使用了一个更简单的解决方案。
所以我有一个 Rails 应用程序需要处理来自不同邮件服务器(也包括 Outlook)的 iCalendar 文件,这导致在尝试解释 Microsoft 时区时出现问题。
由于 属性 问题,我无法在此处 post 我的完整代码,但事情就是这样:
1) 每次启动程序时,从 CLDR 项目主机下载 windowsZone.xml 映射文件。
2) 在验证时区字符串时,首先检查 Ruby 个时区:
ActiveSupport::TimeZone.all.any? { |tz| tz.name == tzid }
3) 然后从 TZInfo gem:
检查 IANA 时区
TZInfo::TimezoneProxy.all.any? { |tz| tz.identifier == tzid }
4) 如果您有 Microsoft 时区,请检查您的映射文件,Nokogiri::XML 非常有帮助。
5) 否则发送错误。
这似乎工作正常,我希望我能提供帮助,以防有人在 2020 年以后遇到这个问题:)
我有一个连接到 SQL 服务器数据库的 rails 应用程序,还有一个连接到同一数据库的 windows 桌面应用程序。 Windows 应用程序正在使用 Microsoft windows 时区数据库,因此我得到了一个像 Pacific Daylight Time
这样的时区名称。在 rails 中,ActiveSupport::TimeZone
class 为我们提供了一个映射散列,其中键类似于 Pacific Time (US & Canada)
,值类似于 America/Los_Angeles
。是否已经有任何东西可以将 windows 格式转换为标准格式以便我可以使用 Time.zone
?
或者是否有一个时区 gem 允许我配置 rails 以使用 windows 格式?
这是我已经开始帮助转换的数组,但有一点我不是 100% 确定。
DAYLIGHT = [
{name: 'Dateline Daylight Time', offset: -12, alt: 'International Date Line West'},
{name: 'UTC-11', offset: -11, alt: ''},
{name: 'Hawaiian Daylight Time', offset: -10, alt: 'Hawaii'},
{name: 'Alaskan Daylight Time', offset: -9, alt: 'Alaska'},
{name: 'Pacific Daylight Time (Mexico)', offset: -8, alt: ''},
{name: 'Pacific Daylight Time', offset: -8, alt: 'Pacific Time (US & Canada)'},
{name: 'US Mountain Daylight Time', offset: -7, alt: 'Mountain Time (US & Canada)'},
{name: 'Mountain Daylight Time (Mexico)', offset: -7, alt: ''},
{name: 'Mountain Daylight Time', offset: -7, alt: 'Mountain Time (US & Canada)'},
{name: 'Central America Daylight Time', offset: -6, alt: 'Central Time (US & Canada)'},
{name: 'Central Daylight Time', offset: -6, alt: 'Central Time (US & Canada)'},
{name: 'Central Daylight Time (Mexico)', offset: -6, alt: ''},
{name: 'Canada Central Daylight Time', offset: -6, alt: ''},
{name: 'SA Pacific Daylight Time', offset: -5, alt: ''},
{name: 'Eastern Daylight Time', offset: -5, alt: 'Eastern Time (US & Canada)'},
{name: 'US Eastern Daylight Time', offset: -5, alt: 'Eastern Time (US & Canada)'},
{name: 'Venezuela Daylight Time', offset: -4.5, alt: ''},
{name: 'Paraguay Daylight Time', offset: -4, alt: ''},
{name: 'Atlantic Daylight Time', offset: -4, alt: ''},
{name: 'Central Brazilian Daylight Time', offset: -4, alt: ''},
{name: 'SA Western Daylight Time', offset: -4, alt: ''},
{name: 'Pacific SA Daylight Time', offset: -4, alt: ''},
{name: 'Newfoundland Daylight Time', offset: -3.5, alt: ''},
{name: 'E. South America Daylight Time', offset: -3, alt: ''},
{name: 'Argentina Daylight Time', offset: -3, alt: ''},
{name: 'SA Eastern Daylight Time', offset: -3, alt: ''},
{name: 'Greenland Daylight Time', offset: -3, alt: ''},
{name: 'Montevideo Daylight Time', offset: -3, alt: ''},
{name: 'Bahia Daylight Time', offset: -3, alt: ''},
{name: 'UTC-02', offset: -2, alt: ''},
{name: 'Mid-Atlantic Daylight Time', offset: -2, alt: ''},
{name: 'Azores Daylight Time', offset: -1, alt: ''},
{name: 'Cabo Verde Daylight Time', offset: -1, alt: ''},
{name: 'Morocco Daylight Time', offset: 0, alt: ''},
{name: 'Coordinated Universal Time', offset: 0, alt: ''},
{name: 'GMT Daylight Time', offset: 0, alt: ''},
{name: 'Greenwich Daylight Time', offset: 0, alt: ''},
{name: 'W. Europe Daylight Time', offset: 1, alt: ''},
{name: 'Central Europe Daylight Time', offset: 1, alt: ''},
{name: 'Romance Daylight Time', offset: 1, alt: ''},
{name: 'Central European Daylight Time', offset: 1, alt: ''},
{name: 'W. Central Africa Daylight Time', offset: 1, alt: ''},
{name: 'Namibia Daylight Time', offset: 1, alt: ''},
{name: 'Jordan Daylight Time', offset: 2, alt: ''},
{name: 'GTB Daylight Time', offset: 2, alt: ''},
{name: 'Middle East Daylight Time', offset: 2, alt: ''},
{name: 'Egypt Daylight Time', offset: 2, alt: ''},
{name: 'Syria Daylight Time', offset: 2, alt: ''},
{name: 'E. Europe Daylight Time', offset: 2, alt: ''},
{name: 'South Africa Daylight Time', offset: 2, alt: ''},
{name: 'FLE Daylight Time', offset: 2, alt: ''},
{name: 'Turkey Daylight Time', offset: 2, alt: ''},
{name: 'Jerusalem Daylight Time', offset: 2, alt: ''},
{name: 'Russia TZ 1 Daylight Time', offset: 2, alt: ''},
{name: 'Libya Daylight Time', offset: 2, alt: ''},
{name: 'Arabic Daylight Time', offset: 3, alt: ''},
{name: 'Arab Daylight Time', offset: 3, alt: ''},
{name: 'Belarus Daylight Time', offset: 3, alt: ''},
{name: 'Russia TZ 2 Daylight Time', offset: 3, alt: ''},
{name: 'E. Africa Daylight Time', offset: 3, alt: ''},
{name: 'Iran Daylight Time', offset: 3.5, alt: ''},
{name: 'Arabian Daylight Time', offset: 4, alt: ''},
{name: 'Azerbaijan Daylight Time', offset: 4, alt: ''},
{name: 'Russia TZ 3 Daylight Time', offset: 4, alt: ''},
{name: 'Mauritius Daylight Time', offset: 4, alt: ''},
{name: 'Georgian Daylight Time', offset: 4, alt: ''},
{name: 'Caucasus Daylight Time', offset: 4, alt: ''},
{name: 'Afghanistan Daylight Time', offset: 4.5, alt: ''},
{name: 'West Asia Daylight Time', offset: 5, alt: ''},
{name: 'Russia TZ 4 Daylight Time', offset: 5, alt: ''},
{name: 'Pakistan Daylight Time', offset: 5, alt: ''},
{name: 'India Daylight Time', offset: 5.5, alt: ''},
{name: 'Sri Lanka Daylight Time', offset: 5.5, alt: ''},
{name: 'Nepal Daylight Time', offset: 5.75, alt: ''},
{name: 'Central Asia Daylight Time', offset: 6, alt: ''},
{name: 'Bangladesh Daylight Time', offset: 6, alt: ''},
{name: 'Russia TZ 5 Daylight Time', offset: 6, alt: ''},
{name: 'Myanmar Daylight Time', offset: 6.5, alt: ''},
{name: 'SE Asia Daylight Time', offset: 7, alt: ''},
{name: 'Russia TZ 6 Daylight Time', offset: 7, alt: ''},
{name: 'China Daylight Time', offset: 8, alt: ''},
{name: 'Russia TZ 7 Daylight Time', offset: 8, alt: ''},
{name: 'Malay Peninsula Daylight Time', offset: 8, alt: ''},
{name: 'W. Australia Daylight Time', offset: 8, alt: ''},
{name: 'Taipei Daylight Time', offset: 8, alt: ''},
{name: 'Ulaanbaatar Daylight Time', offset: 8, alt: ''},
{name: 'Tokyo Daylight Time', offset: 9, alt: ''},
{name: 'Korea Daylight Time', offset: 9, alt: ''},
{name: 'Russia TZ 8 Daylight Time', offset: 9, alt: ''},
{name: 'Cen. Australia Daylight Time', offset: 9.5, alt: ''},
{name: 'AUS Central Daylight Time', offset: 9.5, alt: ''},
{name: 'E. Australia Daylight Time', offset: 10, alt: ''},
{name: 'AUS Eastern Daylight Time', offset: 10, alt: ''},
{name: 'West Pacific Daylight Time', offset: 10, alt: ''},
{name: 'Tasmania Daylight Time', offset: 10, alt: ''},
{name: 'Magadan Daylight Time', offset: 10, alt: ''},
{name: 'Russia TZ 9 Daylight Time', offset: 10, alt: ''},
{name: 'Russia TZ 10 Daylight Time', offset: 11, alt: ''},
{name: 'Central Pacific Daylight Time', offset: 11, alt: ''},
{name: 'Russia TZ 11 Daylight Time', offset: 12, alt: ''},
{name: 'New Zealand Daylight Time', offset: 12, alt: ''},
{name: 'UTC+12', offset: 12, alt: ''},
{name: 'Fiji Daylight Time', offset: 12, alt: ''},
{name: 'Kamchatka Daylight Time', offset: 12, alt: ''},
{name: 'Tonga Daylight Time', offset: 13, alt: ''},
{name: 'Samoa Daylight Time', offset: 13, alt: ''},
{name: 'Line Islands Daylight Time', offset: 14, alt: ''}
]
改进答案
我的原始答案(下方)中描述的功能现在可以在我的 TimeZoneConverter .NET 库中使用。所有艰苦的工作都为您完成,并随着世界时区的变化而不断更新。项目自述文件中的示例展示了如何在 Windows、IANA 和 Rails 标识符之间进行转换。
由于问题中描述的应用程序在 Rails 中,我建议 运行 在 .NET 中进行后台作业,将 Windows 时区 ID 转换为 Rails 应用并将它们放在单独的列中。
原答案
您要查找的资源是作为 Unicode CLDR project. The file is located within the CLDR release at common/supplemental/windowsZones.xml
, and you can find the current "development version" of it here.
注意几点:
文件 会随着 Microsoft 和 IANA 的新时区更新,或者偶尔当政府大幅更改时区规则以致应用不同的映射。
您列表中的偏移量只是 标准 偏移量 - 即在夏令时无效时应用的偏移量。 “时区”由标准偏移量、夏令时偏移量、DST 转换的特定日期和时间以及偏移量和转换的更改历史组成。
不应在 Rails 以外的任何地方使用 Rails 时区名称。我的理解是,它们实际上是在 Rails 决定使用标准 IANA/Olson 时区之前创建的,然后在 Ruby tzinfo gem became viable, the Rails zones were retrofitted through the
MAPPING
constant shown on this page ,然后随着个人投诉的出现而添加了一些。如果可能,通过 tzinfo gem 直接使用 IANA 时区。如果没有,那么您将需要经过两层映射(Microsoft -> IANA -> Rails)。我不知道 CLDR 映射的 Rails 特定实现。我检查了 Rails 项目的几个 CLDR,发现它们不包括 CLDR 的特定部分。但是,如果您可以控制 Windows 方面的事情,那么您可以考虑使用我描述的 in this answer 的 .NET 实现。您可以在 Windows 端进行 Windows 到 IANA 的转换,然后直接将 IANA 区域与 tzinfo 一起使用,或者映射到 Rails 应用中的 Rails 区域。
也意识到 Rails 时区的数量明显少于 IANA 支持的数量。我没有检查过,但很可能某些 Windows 区域映射到不在 Rails 中的 IANA 区域。此外,有些 Rails 区域有多个 Rails 条目,但只有一个 IANA 映射 - 本质上使它们成为等效别名。
Rails和Windows都使用“UTC”作为区域id,Rails映射到“Etc/UTC”,但是CLDR映射到“Etc/GMT”。你必须手动处理这个。
最后,认识到 CLDR 使用“稳定”标识符的方式与 IANA 的“规范”标识符不同,这可能会在映射过程中造成一些困难。
例如,考虑 Microsoft 区域“印度标准时间”映射到 CLDR 中的“Asia/Calcutta”,因为那是 原始 IANA 区域是。但是,IANA 将区域更改为“Asia/Kolkata”,并为“Asia/Calcutta”设置了 link 以向后兼容。当您查看 Rails
MAPPING
常量时,有四个 Rails 区域,“Chennai”、“Kolkata”、“Mumbai”和“New Delhi”——所有这些区域都已映射到“Asia/Kolkata”。为了克服这个问题,您将还 需要来自 CLDR 的另一个文件,
common/bcp47/timezone.xml
。您可以使用此文件查找别名 IANA 区域之间的所有 link,这可以帮助您映射回 Rails 区域。
所以是的,这是可能的 - 但这并不容易。 ;)
我已经为你做了当前映射,如下:
"Windows","IANA","Rails"
"W. Central Africa Standard Time","Africa/Algiers","West Central Africa"
"Egypt Standard Time","Africa/Cairo","Cairo"
"Morocco Standard Time","Africa/Casablanca","Casablanca"
"South Africa Standard Time","Africa/Harare","Harare"
"South Africa Standard Time","Africa/Johannesburg","Pretoria"
"Greenwich Standard Time","Africa/Monrovia","Monrovia"
"E. Africa Standard Time","Africa/Nairobi","Nairobi"
"Argentina Standard Time","America/Argentina/Buenos_Aires","Buenos Aires"
"SA Pacific Standard Time","America/Bogota","Bogota"
"Venezuela Standard Time","America/Caracas","Caracas"
"Central Standard Time","America/Chicago","Central Time (US & Canada)"
"Mountain Standard Time (Mexico)","America/Chihuahua","Chihuahua"
"Mountain Standard Time","America/Denver","Mountain Time (US & Canada)"
"Greenland Standard Time","America/Godthab","Greenland"
"Central America Standard Time","America/Guatemala","Central America"
"SA Western Standard Time","America/Guyana","Georgetown"
"Atlantic Standard Time","America/Halifax","Atlantic Time (Canada)"
"US Eastern Standard Time","America/Indiana/Indianapolis","Indiana (East)"
"Alaskan Standard Time","America/Juneau","Alaska"
"SA Western Standard Time","America/La_Paz","La Paz"
"SA Pacific Standard Time","America/Lima","Lima"
"SA Pacific Standard Time","America/Lima","Quito"
"Pacific Standard Time","America/Los_Angeles","Pacific Time (US & Canada)"
"Mountain Standard Time (Mexico)","America/Mazatlan","Mazatlan"
"Central Standard Time (Mexico)","America/Mexico_City","Guadalajara"
"Central Standard Time (Mexico)","America/Mexico_City","Mexico City"
"Central Standard Time (Mexico)","America/Monterrey","Monterrey"
"Montevideo Standard Time","America/Montevideo","Montevideo"
"Eastern Standard Time","America/New_York","Eastern Time (US & Canada)"
"US Mountain Standard Time","America/Phoenix","Arizona"
"Canada Central Standard Time","America/Regina","Saskatchewan"
"Pacific SA Standard Time","America/Santiago","Santiago"
"E. South America Standard Time","America/Sao_Paulo","Brasilia"
"Newfoundland Standard Time","America/St_Johns","Newfoundland"
"Pacific Standard Time","America/Tijuana","Tijuana"
"Central Asia Standard Time","Asia/Almaty","Almaty"
"Arabic Standard Time","Asia/Baghdad","Baghdad"
"Azerbaijan Standard Time","Asia/Baku","Baku"
"SE Asia Standard Time","Asia/Bangkok","Bangkok"
"SE Asia Standard Time","Asia/Bangkok","Hanoi"
"China Standard Time","Asia/Chongqing","Chongqing"
"Sri Lanka Standard Time","Asia/Colombo","Sri Jayawardenepura"
"Bangladesh Standard Time","Asia/Dhaka","Astana"
"Bangladesh Standard Time","Asia/Dhaka","Dhaka"
"China Standard Time","Asia/Hong_Kong","Hong Kong"
"North Asia East Standard Time","Asia/Irkutsk","Irkutsk"
"SE Asia Standard Time","Asia/Jakarta","Jakarta"
"Israel Standard Time","Asia/Jerusalem","Jerusalem"
"Afghanistan Standard Time","Asia/Kabul","Kabul"
"Russia Time Zone 11","Asia/Kamchatka","Kamchatka"
"Pakistan Standard Time","Asia/Karachi","Islamabad"
"Pakistan Standard Time","Asia/Karachi","Karachi"
"Nepal Standard Time","Asia/Kathmandu","Kathmandu"
"India Standard Time","Asia/Kolkata","Chennai"
"India Standard Time","Asia/Kolkata","Kolkata"
"India Standard Time","Asia/Kolkata","Mumbai"
"India Standard Time","Asia/Kolkata","New Delhi"
"North Asia Standard Time","Asia/Krasnoyarsk","Krasnoyarsk"
"Singapore Standard Time","Asia/Kuala_Lumpur","Kuala Lumpur"
"Arab Standard Time","Asia/Kuwait","Kuwait"
"Magadan Standard Time","Asia/Magadan","Magadan"
"Arabian Standard Time","Asia/Muscat","Abu Dhabi"
"Arabian Standard Time","Asia/Muscat","Muscat"
"N. Central Asia Standard Time","Asia/Novosibirsk","Novosibirsk"
"Myanmar Standard Time","Asia/Rangoon","Rangoon"
"Arab Standard Time","Asia/Riyadh","Riyadh"
"Korea Standard Time","Asia/Seoul","Seoul"
"China Standard Time","Asia/Shanghai","Beijing"
"Singapore Standard Time","Asia/Singapore","Singapore"
"Russia Time Zone 10","Asia/Srednekolymsk","Srednekolymsk"
"Taipei Standard Time","Asia/Taipei","Taipei"
"West Asia Standard Time","Asia/Tashkent","Tashkent"
"Georgian Standard Time","Asia/Tbilisi","Tbilisi"
"Iran Standard Time","Asia/Tehran","Tehran"
"Tokyo Standard Time","Asia/Tokyo","Osaka"
"Tokyo Standard Time","Asia/Tokyo","Sapporo"
"Tokyo Standard Time","Asia/Tokyo","Tokyo"
"Ulaanbaatar Standard Time","Asia/Ulaanbaatar","Ulaanbaatar"
"Central Asia Standard Time","Asia/Urumqi","Urumqi"
"Vladivostok Standard Time","Asia/Vladivostok","Vladivostok"
"Yakutsk Standard Time","Asia/Yakutsk","Yakutsk"
"Ekaterinburg Standard Time","Asia/Yekaterinburg","Ekaterinburg"
"Caucasus Standard Time","Asia/Yerevan","Yerevan"
"Azores Standard Time","Atlantic/Azores","Azores"
"Cape Verde Standard Time","Atlantic/Cape_Verde","Cape Verde Is."
"UTC-02","Atlantic/South_Georgia","Mid-Atlantic"
"Cen. Australia Standard Time","Australia/Adelaide","Adelaide"
"E. Australia Standard Time","Australia/Brisbane","Brisbane"
"AUS Central Standard Time","Australia/Darwin","Darwin"
"Tasmania Standard Time","Australia/Hobart","Hobart"
"AUS Eastern Standard Time","Australia/Melbourne","Canberra"
"AUS Eastern Standard Time","Australia/Melbourne","Melbourne"
"W. Australia Standard Time","Australia/Perth","Perth"
"AUS Eastern Standard Time","Australia/Sydney","Sydney"
"UTC","Etc/UTC","UTC"
"W. Europe Standard Time","Europe/Amsterdam","Amsterdam"
"GTB Standard Time","Europe/Athens","Athens"
"Central Europe Standard Time","Europe/Belgrade","Belgrade"
"W. Europe Standard Time","Europe/Berlin","Berlin"
"W. Europe Standard Time","Europe/Berlin","Bern"
"Central Europe Standard Time","Europe/Bratislava","Bratislava"
"Romance Standard Time","Europe/Brussels","Brussels"
"GTB Standard Time","Europe/Bucharest","Bucharest"
"Central Europe Standard Time","Europe/Budapest","Budapest"
"Romance Standard Time","Europe/Copenhagen","Copenhagen"
"GMT Standard Time","Europe/Dublin","Dublin"
"FLE Standard Time","Europe/Helsinki","Helsinki"
"Turkey Standard Time","Europe/Istanbul","Istanbul"
"Kaliningrad Standard Time","Europe/Kaliningrad","Kaliningrad"
"FLE Standard Time","Europe/Kiev","Kyiv"
"GMT Standard Time","Europe/Lisbon","Lisbon"
"Central Europe Standard Time","Europe/Ljubljana","Ljubljana"
"GMT Standard Time","Europe/London","Edinburgh"
"GMT Standard Time","Europe/London","London"
"Romance Standard Time","Europe/Madrid","Madrid"
"Belarus Standard Time","Europe/Minsk","Minsk"
"Russian Standard Time","Europe/Moscow","Moscow"
"Russian Standard Time","Europe/Moscow","St. Petersburg"
"Romance Standard Time","Europe/Paris","Paris"
"Central Europe Standard Time","Europe/Prague","Prague"
"FLE Standard Time","Europe/Riga","Riga"
"W. Europe Standard Time","Europe/Rome","Rome"
"Russia Time Zone 3","Europe/Samara","Samara"
"Central European Standard Time","Europe/Sarajevo","Sarajevo"
"Central European Standard Time","Europe/Skopje","Skopje"
"FLE Standard Time","Europe/Sofia","Sofia"
"W. Europe Standard Time","Europe/Stockholm","Stockholm"
"FLE Standard Time","Europe/Tallinn","Tallinn"
"W. Europe Standard Time","Europe/Vienna","Vienna"
"FLE Standard Time","Europe/Vilnius","Vilnius"
"Russian Standard Time","Europe/Volgograd","Volgograd"
"Central European Standard Time","Europe/Warsaw","Warsaw"
"Central European Standard Time","Europe/Zagreb","Zagreb"
"Samoa Standard Time","Pacific/Apia","Samoa"
"New Zealand Standard Time","Pacific/Auckland","Auckland"
"New Zealand Standard Time","Pacific/Auckland","Wellington"
"Tonga Standard Time","Pacific/Fakaofo","Tokelau Is."
"Fiji Standard Time","Pacific/Fiji","Fiji"
"Central Pacific Standard Time","Pacific/Guadalcanal","Solomon Is."
"West Pacific Standard Time","Pacific/Guam","Guam"
"Hawaiian Standard Time","Pacific/Honolulu","Hawaii"
"UTC+12","Pacific/Majuro","Marshall Is."
"UTC-11","Pacific/Midway","International Date Line West"
"UTC-11","Pacific/Midway","Midway Island"
"Central Pacific Standard Time","Pacific/Noumea","New Caledonia"
"UTC-11","Pacific/Pago_Pago","American Samoa"
"West Pacific Standard Time","Pacific/Port_Moresby","Port Moresby"
"Tonga Standard Time","Pacific/Tongatapu","Nuku'alofa"
请注意,上面的列表包括多个 Rails 区域映射回同一 Windows 区域的条目。在 Windows 到 Rails 方向映射时,您可能只想选择其中之一。
此外,上面的列表不包括无法映射的区域,如下(CSV):
"Windows","IANA","Rails"
"","Pacific/Chatham","Chatham Is."
"Dateline Standard Time","Etc/GMT+12",""
"Pacific Standard Time (Mexico)","America/Santa_Isabel",""
"Eastern Standard Time (Mexico)","America/Cancun",""
"Paraguay Standard Time","America/Asuncion",""
"Central Brazilian Standard Time","America/Cuiaba",""
"SA Eastern Standard Time","America/Cayenne",""
"Bahia Standard Time","America/Bahia",""
"Namibia Standard Time","Africa/Windhoek",""
"Jordan Standard Time","Asia/Amman",""
"Middle East Standard Time","Asia/Beirut",""
"Syria Standard Time","Asia/Damascus",""
"E. Europe Standard Time","Etc/GMT-2",""
"Libya Standard Time","Africa/Tripoli",""
"Mauritius Standard Time","Indian/Mauritius",""
"Line Islands Standard Time","Pacific/Kiritimati",""
感谢@MattJohnson-Pint,经过很长时间的研究,我能够解决这个问题,但是我使用了一个更简单的解决方案。
所以我有一个 Rails 应用程序需要处理来自不同邮件服务器(也包括 Outlook)的 iCalendar 文件,这导致在尝试解释 Microsoft 时区时出现问题。
由于 属性 问题,我无法在此处 post 我的完整代码,但事情就是这样:
1) 每次启动程序时,从 CLDR 项目主机下载 windowsZone.xml 映射文件。 2) 在验证时区字符串时,首先检查 Ruby 个时区:
ActiveSupport::TimeZone.all.any? { |tz| tz.name == tzid }
3) 然后从 TZInfo gem:
检查 IANA 时区TZInfo::TimezoneProxy.all.any? { |tz| tz.identifier == tzid }
4) 如果您有 Microsoft 时区,请检查您的映射文件,Nokogiri::XML 非常有帮助。
5) 否则发送错误。
这似乎工作正常,我希望我能提供帮助,以防有人在 2020 年以后遇到这个问题:)