runsisi's

technical notes

制作支持自定义夏令时的 tzdata rpm 包

2019-01-31 runsisi#ntp

对于某些需要自定义夏令时的需求,CentOS 自带的 tzdata 不能满足要求,因此需要自定义 tzdata,我们可以通过修改 tzdata 定义文件进行实现。下面以修改 Asia/Shanghai 即我国的夏令时为例进行说明。

tzdata 的数据可以在 iana 官方的 ftp 上下载:

ftp://ftp.iana.org/tz/releases/

也可以修改 CentOS 官方的源代码:

http://vault.centos.org/7.5.1804/os/Source/SPackages/tzdata-2018c-1.el7.src.rpm

通常来说我们当然是修改 CentOS 官方的源代码来实现,因为我们需要制作 rpm 包。

首先安装 tzdata-2018c-1.el7.src.rpm,然后切换到 ~/rpmbuild/SOURCES/ 目录修改 tzdata2018c.tar.gz 中 asia 文件定义的规则。

假设我们想要从 2017 年开始,在每年 9 月的第一个满足日期条件的周日,日期条件为 >= 9月10日,那一天 0 点进入夏令时,然后在 10 月的第一个满足日期条件的周日,日期条件为 >= 10 月 1 日,那一天 0 点退出夏令时,则需要在 PRC(即中华人民共和国)的规则之下增加两条规则如下(在 /usr/share/zoneinfo 中,Asia/Shanghai 是指向 PRC 的符号链接):

Rule    PRC 2017    max -   Sep Sun>=10 0:00    1:00    D
Rule    PRC 2017    max -   Oct Sun>=1  0:00    0   S

然后重新打包 tzdata2018c.tar.gz(注意这个 tar.gz 包没有文件夹),最后重新制作 rpm 包:

 ~$ rpmbuild -ba ~/rpmbuild/SPECS/tzdata.spec

安装新制作的 tzdata 包,查看 Asia/Shanghai 的夏令时信息如下:

~$ zdump -v Asia/Shanghai
Asia/Shanghai  -9223372036854775808 = NULL
Asia/Shanghai  -9223372036854689408 = NULL
Asia/Shanghai  Mon Dec 31 15:54:16 1900 UTC = Mon Dec 31 23:59:59 1900 LMT isdst=0 gmtoff=29143
Asia/Shanghai  Mon Dec 31 15:54:17 1900 UTC = Mon Dec 31 23:54:17 1900 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sun Jun  2 15:59:59 1940 UTC = Sun Jun  2 23:59:59 1940 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sun Jun  2 16:00:00 1940 UTC = Mon Jun  3 01:00:00 1940 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Mon Sep 30 14:59:59 1940 UTC = Mon Sep 30 23:59:59 1940 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Mon Sep 30 15:00:00 1940 UTC = Mon Sep 30 23:00:00 1940 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Mar 15 15:59:59 1941 UTC = Sat Mar 15 23:59:59 1941 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Mar 15 16:00:00 1941 UTC = Sun Mar 16 01:00:00 1941 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Tue Sep 30 14:59:59 1941 UTC = Tue Sep 30 23:59:59 1941 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Tue Sep 30 15:00:00 1941 UTC = Tue Sep 30 23:00:00 1941 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat May  3 15:59:59 1986 UTC = Sat May  3 23:59:59 1986 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat May  3 16:00:00 1986 UTC = Sun May  4 01:00:00 1986 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 13 14:59:59 1986 UTC = Sat Sep 13 23:59:59 1986 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 13 15:00:00 1986 UTC = Sat Sep 13 23:00:00 1986 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Apr 11 15:59:59 1987 UTC = Sat Apr 11 23:59:59 1987 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Apr 11 16:00:00 1987 UTC = Sun Apr 12 01:00:00 1987 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 12 14:59:59 1987 UTC = Sat Sep 12 23:59:59 1987 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 12 15:00:00 1987 UTC = Sat Sep 12 23:00:00 1987 CST isdst=0 gmtoff=28800
...
Asia/Shanghai  Sat Apr 13 15:59:59 1991 UTC = Sat Apr 13 23:59:59 1991 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Apr 13 16:00:00 1991 UTC = Sun Apr 14 01:00:00 1991 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 14 14:59:59 1991 UTC = Sat Sep 14 23:59:59 1991 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 14 15:00:00 1991 UTC = Sat Sep 14 23:00:00 1991 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Sep  9 15:59:59 2017 UTC = Sat Sep  9 23:59:59 2017 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Sep  9 16:00:00 2017 UTC = Sun Sep 10 01:00:00 2017 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 30 14:59:59 2017 UTC = Sat Sep 30 23:59:59 2017 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 30 15:00:00 2017 UTC = Sat Sep 30 23:00:00 2017 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Sep 15 15:59:59 2018 UTC = Sat Sep 15 23:59:59 2018 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Sep 15 16:00:00 2018 UTC = Sun Sep 16 01:00:00 2018 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Oct  6 14:59:59 2018 UTC = Sat Oct  6 23:59:59 2018 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Oct  6 15:00:00 2018 UTC = Sat Oct  6 23:00:00 2018 CST isdst=0 gmtoff=28800
...
Asia/Shanghai  Sat Sep 10 15:59:59 2022 UTC = Sat Sep 10 23:59:59 2022 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Sep 10 16:00:00 2022 UTC = Sun Sep 11 01:00:00 2022 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Oct  1 14:59:59 2022 UTC = Sat Oct  1 23:59:59 2022 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Oct  1 15:00:00 2022 UTC = Sat Oct  1 23:00:00 2022 CST isdst=0 gmtoff=28800
...

而 CentOS 自带的 tzdata 包 Asia/Shanghai 夏令时信息如下:

~$ zdump -v Asia/Shanghai
Asia/Shanghai  -9223372036854775808 = NULL
Asia/Shanghai  -9223372036854689408 = NULL
Asia/Shanghai  Mon Dec 31 15:54:16 1900 UTC = Mon Dec 31 23:59:59 1900 LMT isdst=0 gmtoff=29143
Asia/Shanghai  Mon Dec 31 15:54:17 1900 UTC = Mon Dec 31 23:54:17 1900 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sun Jun  2 15:59:59 1940 UTC = Sun Jun  2 23:59:59 1940 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sun Jun  2 16:00:00 1940 UTC = Mon Jun  3 01:00:00 1940 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Mon Sep 30 14:59:59 1940 UTC = Mon Sep 30 23:59:59 1940 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Mon Sep 30 15:00:00 1940 UTC = Mon Sep 30 23:00:00 1940 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Mar 15 15:59:59 1941 UTC = Sat Mar 15 23:59:59 1941 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Mar 15 16:00:00 1941 UTC = Sun Mar 16 01:00:00 1941 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Tue Sep 30 14:59:59 1941 UTC = Tue Sep 30 23:59:59 1941 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Tue Sep 30 15:00:00 1941 UTC = Tue Sep 30 23:00:00 1941 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat May  3 15:59:59 1986 UTC = Sat May  3 23:59:59 1986 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat May  3 16:00:00 1986 UTC = Sun May  4 01:00:00 1986 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 13 14:59:59 1986 UTC = Sat Sep 13 23:59:59 1986 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 13 15:00:00 1986 UTC = Sat Sep 13 23:00:00 1986 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Apr 11 15:59:59 1987 UTC = Sat Apr 11 23:59:59 1987 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Apr 11 16:00:00 1987 UTC = Sun Apr 12 01:00:00 1987 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 12 14:59:59 1987 UTC = Sat Sep 12 23:59:59 1987 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 12 15:00:00 1987 UTC = Sat Sep 12 23:00:00 1987 CST isdst=0 gmtoff=28800
...
Asia/Shanghai  Sat Apr 13 15:59:59 1991 UTC = Sat Apr 13 23:59:59 1991 CST isdst=0 gmtoff=28800
Asia/Shanghai  Sat Apr 13 16:00:00 1991 UTC = Sun Apr 14 01:00:00 1991 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 14 14:59:59 1991 UTC = Sat Sep 14 23:59:59 1991 CDT isdst=1 gmtoff=32400
Asia/Shanghai  Sat Sep 14 15:00:00 1991 UTC = Sat Sep 14 23:00:00 1991 CST isdst=0 gmtoff=28800
Asia/Shanghai  9223372036854689407 = NULL
Asia/Shanghai  9223372036854775807 = NULL

参考资料

A literary appreciation of the Olson/Zoneinfo/tz database

https://blog.jonudell.net/2009/10/23/a-literary-appreciation-of-the-olsonzoneinfotz-database/

Creating Custom TimeZoneInfo With Daylight Saving Time Transitions

https://www.appliedis.com/creating-custom-timezoneinfo-with-daylight-saving-time-transitions/