I don't know if I am doing something stupid, so bear with me.
tl;dr Rails ActiveSupport time and timezone seems to have an error on Alpine Linux. It uses the DST variant (summer time) of my timezone when it should use the winter time.
Steps to reproduce:
$ docker run -it --rm ruby:2.7.1-alpine sh
All following steps happen inside the running docker container.
$ 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
Looks good. Time is printed in UTC.
Time
class can only handle local time. This is dependent on the local system timezone, which can be configured using operating system configuration mechanisms, or which can simply be passed to Ruby with the TZ
env var. Let's try to use my timezone "Europe/Berlin":$ TZ="Europe/Berlin" ruby -e 'puts Time.now.inspect'
2020-10-28 21:39:22.7037648 +0100
Looks good. Berlin timezone is UTC+01 in winter (standard) or UTC+02 in summer (DST). At the time of this writing, we have winter time, so +0100
is fine.
$ 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
Time.current
, so let's try this:$ ruby -e 'require "active_support/all"; puts Time.current.inspect'
2020-10-28 20:43:51.1098842 +0000
This looks not different from the output of step 3. The reason for this is that Time.current
only behaves differently than Time.now
when a timezone is configured.
Time.zone=(timezone_identifier)
or with Time.use_zone(timezone_identifier) { "inside this block the timezone is used" }
. Let's try the first variant:$ ruby -e 'require "active_support/all"; Time.zone = "UTC"; puts Time.current.inspect'
Wed, 28 Oct 2020 20:50:55 UTC +00:00
We are still on UTC, but the output looks different than before. From this we know that we got a ActiveSupport::TimeWithZone
object. This is good.
$ ruby -e 'require "active_support/all"; Time.zone = "Europe/Berlin"; puts Time.current.inspect'
Wed, 28 Oct 2020 22:52:21 CEST +02:00
On a first glance this looks good, but compare it carefully with the output of step 4. In "Europe/Berlin" timezone we currently have winter time, UTC+01, also called "CET" (central european time). But this time in the output the timestamp is labeled as being "CEST" (central european summer time), which is UTC+02.
And this is wrong.
Where is the error? Is it in Alpine Linux? Is it in standard Ruby? But the output is correct in step 4. Or is the error in ActiveSupport or its connection to the timezone data? Am I doing something wrong?
Turns out this is an issue affecting the tzinfo
gem (versions < 1.2.8
/ < 2.0.3
) - it's incompatible with timezone-data 2020b (onwards?), and recent versions of Alpine ship with 2020c. The file format changed from 'fat' to 'slim' which isn't compatible with the tzinfo
gem yet.
Support for "slim" format zoneinfo files has now been added to the tzinfo
gem in releases:
You can use the tzinfo-data
gem instead of relying on the system tzinfo:
gem install activesupport tzinfo-data
ruby -e 'require "active_support/all"; Time.zone = "Europe/Berlin"; puts TZInfo::DataSource.get; puts Time.current.inspect'
# Ruby DataSource
# Thu, 29 Oct 2020 16:25:08 CET +01:00
You can rebuild the time zone data package in the 'fat' format (adapted from comment):
FROM ruby:2.7.2-alpine
# Install tzdata because we need the zic binary
RUN apk add --no-cache tzdata
# Fix incompatibility with slim tzdata from 2020b onwards
RUN wget https://data.iana.org/time-zones/tzdb/tzdata.zi -O /usr/share/zoneinfo/tzdata.zi && \
/usr/sbin/zic -b fat /usr/share/zoneinfo/tzdata.zi
Then testing the time in Europe/Berlin
:
gem install activesupport
ruby -e 'require "active_support/all"; Time.zone = "Europe/Berlin"; puts TZInfo::DataSource.get; puts Time.current.inspect'
# Zoneinfo DataSource: /usr/share/zoneinfo
# Thu, 29 Oct 2020 16:29:19 CET +01:00
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With