【发布时间】:2021-02-11 07:32:58
【问题描述】:
我不知道我是不是在做傻事,所以请耐心等待。
tl;dr Rails ActiveSupport 时间和时区在 Alpine Linux 上似乎有错误。当它应该使用冬季时间时,它使用我的时区的 DST 变体(夏令时)。
重现步骤:
- 在 Docker Alpine Linux Ruby 映像中启动 shell:
$ docker run -it --rm ruby:2.7.1-alpine sh
以下所有步骤都发生在正在运行的 docker 容器内。
- 安装时区数据:
$ apk add --no-cache --update tzdata
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
(1/1) Installing tzdata (2020c-r0)
Executing busybox-1.31.1-r9.trigger
OK: 23 MiB in 37 packages
- 打印标准红宝石当前时间:
$ ruby -e 'puts Time.now.inspect'
2020-10-28 20:34:24.4817918 +0000
看起来不错。时间以 UTC 打印。
- 除了 UTC,标准 ruby
Time类只能处理当地时间。这取决于本地系统时区,可以使用操作系统配置机制进行配置,或者可以简单地使用TZenv var 将其传递给 Ruby。让我们尝试使用我的时区“欧洲/柏林”:
$ TZ="Europe/Berlin" ruby -e 'puts Time.now.inspect'
2020-10-28 21:39:22.7037648 +0100
看起来不错。柏林时区是冬季的 UTC+01(标准)或夏季的 UTC+02(DST)。在写这篇文章的时候,我们是冬天,所以+0100 很好。
- 现在让我们转到 ActiveSupport:
$ gem install activesupport
Fetching tzinfo-1.2.7.gem
Fetching i18n-1.8.5.gem
Fetching activesupport-6.0.3.4.gem
# #### many more lines of output ####
Successfully installed activesupport-6.0.3.4
6 gems installed
- 与标准 ruby 相比,ActiveSupport 支持所有可能的时区,而不仅仅是两个。获取当前时间是
Time.current,让我们试试这个:
$ ruby -e 'require "active_support/all"; puts Time.current.inspect'
2020-10-28 20:43:51.1098842 +0000
这看起来与步骤 3 的输出没有什么不同。原因是 Time.current 仅在配置时区时的行为与 Time.now 不同。
- 我们可以使用
Time.zone=(timezone_identifier)或Time.use_zone(timezone_identifier) { "inside this block the timezone is used" }为ActiveSupport 配置时区。让我们尝试第一个变体:
$ ruby -e 'require "active_support/all"; Time.zone = "UTC"; puts Time.current.inspect'
Wed, 28 Oct 2020 20:50:55 UTC +00:00
我们仍然使用 UTC,但输出看起来与以前不同。由此我们知道我们得到了一个ActiveSupport::TimeWithZone 对象。这很好。
- 现在我希望我的时区也一样:
$ ruby -e 'require "active_support/all"; Time.zone = "Europe/Berlin"; puts Time.current.inspect'
Wed, 28 Oct 2020 22:52:21 CEST +02:00
乍一看,这看起来不错,但请仔细将其与第 4 步的输出进行比较。在“欧洲/柏林”时区,我们目前有冬季时间,UTC+01,也称为“CET”(中欧时间)。但是这次在输出中时间戳被标记为“CEST”(中欧夏令时),即 UTC+02。
这是错误的。
错误在哪里?它在 Alpine Linux 中吗?它是标准的Ruby吗?但是第 4 步的输出是正确的。还是 ActiveSupport 中的错误或其与时区数据的连接?我做错了吗?
【问题讨论】:
-
欢迎来到 SO!恭喜你提出了一个写得很棒的问题。
-
哦,只是为了避免在这个方向上出现任何问题:当然,我已经检查了第 8 步是否正确运行 - 它产生了所需的输出 - 在非 Alpine 图像上。
-
不仅
#current方法受到影响,ActiveSupport 的所有时区相关方法都受到影响,例如Time.zone.at或Time.zone.parse(如ruby -e 'require "active_support/all"; Time.zone = "Europe/Berlin"; puts Time.zone.at(Time.now.to_i).inspect')。 -
据我所知 ActiveSupport 使用 TZInfo 作为其信息来源。您可能希望将注意力转移到该库以更接近问题的根源。
-
看起来是时候在 Active Report repo 上提交错误报告了
标签: ruby time alpine activesupport