如何序列化Ruby的TZInfo数据?

时间:2013-06-06 21:23:26

标签: javascript ruby-on-rails ruby timezone

我有一个Rails应用程序,像所有Rails应用程序一样,使用Ruby的TZInfo库来获取时区信息。此库使用Olson样式的信息,但实现实际上并不解析Olson文件。定义在Ruby中。

我想确保我的服务器和客户端使用相同的时区数据,以便用户不会遇到任何意外。具体来说,我们在Ruby中修补TZInfo数据的速度比新版本的gem快得多。因此,我考虑并拒绝了以下内容:

  1. 使用内置时区信息的JavaScript库。 Ruby和JavaScript库的数据会有所不同。
  2. 从我的API公开/usr/share/zoneinfo/*的内容。 Ruby和zoneinfo数据会分歧。
  3. 这给我留下了两个选择:

    1. 重写或修补TZInfo以实际解析/usr/share/zoneinfo/*
    2. 中的文件
    3. 想出一种将TZInfo的{​​{1}}对象序列化为JavaScript,JSON,YAML或其他有用格式的方法
    4. 仅告诉客户当前时区偏移量是不够的,因为客户端需要为历史(和未来)日期生成时间戳。

1 个答案:

答案 0 :(得分:2)

在服务器和客户端上使用实现相同版本的IANA时区数据库的库。当前版本(正如我写的那样)是2013c,可以在原始格式here中找到。

在服务器端,使用TZInfo library表示ruby。它有两个宝石,tzinfo gemtzinfo-data gem

如果查看tzinfo-data文档,您会看到有Version属性与IANA版本匹配。所以tzinfo-data 2013.3显示了IANA版本2013c,它也显示在this page上的文档中。

您在评论中提到数据是硬编码的。这不完全正确。它不是硬编码的,而是代码生成的。当您看到the ruby files带有“硬编码”时区数据时,实际上是使用the original IANA source files生成的。有a custom parser执行此操作,因此每次发布新版本的IANA时区数据库时,都可以生成并发布对tzinfo数据的相应更新。

在客户端,您可以使用several different libraries中的任何一个。大多数人都会做同样的事情 - 从相同的IANA来源开始,以及代码生成一个对网络有意义的文件。通常,这是一个JSON文件。

让我们以其中一个库为例 - Walltime-js

我们可以看到on github他们已经链接到github上的IANA/Olson tzdb sources。我们可以通过从git中查看精确版本来确保我们使用完全相同的2013c源数据。

  • 查看tzdb的commit history
  • 在2013年4月19日发现,有评论表明发布2013c。
  • 确认2013 {3}}的2013c版本是2013年4月20日。
  • 所以我们知道2013c的提交ID是f599ad15ce。
  • (是的,如果他们使用git标签会更容易,但出于某种原因他们不会这样做。)

最终,我们通过关注IANA来完成代码生成walltime-data.js文件,进行一次小的更改以确保我们拥有完全相同的2013c源数据。新版本看起来像这样:

git submodule init && git submodule update
git submodule foreach 'git checkout f599ad15ce'
cake data

现在我们有了一个由TZDB 2013c构建的walltime-data.js文件。这将转到客户端并由walltime.js使用。

我们还有2013c的tzinfo-data gem,它将位于服务器上并由Ruby中的tzinfo使用。

因此,需要在它们之间传输的唯一数据是时区的ID,例如America/Los_Angeles。每个库都将使用自己的数据副本和自己的实现,但您可以相信它们指的是相同的东西。

唯一可能使它们表现不同的是,如果它们在解析器或运行时解释数据的方式存在错误。应提请作者注意这些错误。但是你可以避免它们的唯一方法是在两个地方运行 exact 相同的代码和数据 - 这意味着在服务器上使用Node.js而不是Ruby。