2

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

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

  1. 使用内置时区信息的 JavaScript 库。Ruby 和 JavaScript 库的数据会有所不同。
  2. /usr/share/zoneinfo/*从我的 API公开内容。Ruby 和zoneinfo数据会分道扬镳。

这让我有两个选择:

  1. 重写或修补TZInfo以实际解析文件/usr/share/zoneinfo/*
  2. 想出一种将TZInfo'sTimeZone对象序列化为 JavaScript、JSON、YAML 或其他有用格式的方法

仅仅告诉客户端当前时区偏移是不够的,因为客户端需要为历史(和未来)日期生成时间戳。

4

1 回答 1

3

在实现相同版本的 IANA 时区数据库的服务器和客户端上使用库。当前版本(在我写这篇文章的时候)是 2013c,可以在这里找到它的原始形式。

在服务器端,使用 ruby​​ 的TZInfo 库。它有两个 gem,tzinfo gemtzinfo-data gem

如果您查看 tzinfo-data 文档,您将看到有一个Version与 IANA 版本匹配的属性。因此 tzinfo-data 2013.3 显示 IANA 版本 2013c,此页面的文档中也显示了该版本。

您在评论中提到数据是硬编码的。这并不完全正确。它不是硬编码的,它是代码生成的。当您看到带有“硬编码”时区数据的 ruby​​ 文件时,它们实际上是使用原始 IANA 源文件生成的。有一个自定义解析器执行此操作,这样每次发布 IANA 时区数据库的新版本时,都可以生成和发布对 tzinfo-data 的相应更新。

在客户端,您可以使用几个不同的库中的任何一个。大多数人会做完全相同的事情——从相同的 IANA 源开始,并生成对 Web 有意义的文件的代码。通常,这是一个 JSON 文件。

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

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

  • 查看tzdb的提交历史记录。
  • 发现在 2013 年 4 月 19 日,有一条评论指出发布 2013c。
  • 确认IANA发布的 2013c是 2013 年 4 月 20 日。
  • 所以我们知道 2013c 的提交 id 是 f599ad15ce。
  • (是的,如果他们使用 git 标签,这会更容易,但出于某种原因他们不这样做)。

最终,我们最终通过代码生成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. 每个库都将使用自己的数据副本和自己的实现,但您可以相信它们指的是同一个东西。

唯一可能使它们表现不同的是,它们解释数据的方式是否存在错误,无论是在解析器中还是在运行时。此类错误应引起作者的注意。但唯一可能避免它们的方法是在两个地方运行完全相同的代码和数据——这意味着在服务器上使用 Node.js 而不是 Ruby。

于 2013-06-17T14:17:23.277 回答