我有一个Rails应用程序,像所有Rails应用程序一样,它使用Ruby的TZInfo库来获取时区信息。这个库使用Olson风格的信息,但如果实现实际上不解析Olson文件。定义是用Ruby编写的。
我想确保我的服务器和客户端使用相同的时区数据,这样用户就不会遇到任何意外。具体来说,我们在Ruby中修补TZInfo数据的速度比gem的新版本要快得多。因此,我考虑并拒绝了以下内容:
- 使用内置时区信息的JavaScript库。Ruby和JavaScript库的数据将会不同。
- 从我的API中公开
/usr/share/zoneinfo/*
的内容。Ruby和zoneinfo
的数据会出现分歧。
这就给我留下了两个选择:
- 重写或修补
TZInfo
以实际解析/usr/share/zoneinfo/*
中的文件 - 想出一种方法将
TZInfo
的TimeZone
对象序列化为JavaScript, JSON, YAML或其他有用的格式
仅仅告诉客户端当前时区偏移量是不够的,因为客户端需要为历史(和未来)日期生成时间戳。
在服务器和客户端上使用实现相同版本的IANA时区数据库的库。当前版本(当我写这篇文章时)是2013c,可以在这里找到它的原始形式。
在服务器端,使用ruby的TZInfo库。它有两个gem, tzinfo gem和tzinfo-data gem。
如果您查看tzinfo-data文档,您将看到有一个与IANA版本匹配的Version
属性。所以tzinfo-data 2013.3显示的是IANA版本2013c,在本页的文档中也有显示。
您在注释中提到数据是硬编码的。这并不完全正确。它不是硬编码的,而是代码生成的。当您看到带有"硬编码"时区数据的ruby文件时,它们实际上是使用原始IANA源文件生成的。有一个自定义解析器执行此操作,因此每次发布IANA时区数据库的新版本时,都可以生成和发布相应的tzinfo-data更新。
在客户端,可以使用几个不同的库中的任何一个。大多数会做完全相同的事情——从相同的IANA源代码开始,然后生成一个对web有意义的文件。通常,这是一个JSON文件。
让我们以其中一个库为例——Walltime-js。
我们可以在github上看到他们已经链接到IANA/Olson tzdb的github源。我们可以通过从git中查看准确的版本来确保我们使用的是完全相同的2013c源数据。
- 查看tzdb的提交历史。
- 发现在2013年4月19日,有一个注释指示发布2013c.
- 核实2013年4月20日在IANA发布的2013c。
- 所以我们知道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使用。
我们还有2013年的tzinfo-data gem,它将放在服务器上,供tzinfo在Ruby中使用。
因此,它们之间需要传输的唯一数据是时区的id,例如America/Los_Angeles
。每个库将使用自己的数据副本和自己的实现,但您可以相信它们引用的是相同的东西。
唯一可能使它们表现不同的是,如果它们解释数据的方式有错误,要么在解析器中,要么在运行时。这样的错误应该引起作者的注意。但是你唯一可能避免它们的方法是在两个地方运行完全相同的代码和数据——这意味着在服务器上使用Node.js而不是Ruby。