如何使用tzupdater检查和设置Java时区(为openJDK更新tzdata)

时间:2020-02-23 14:40:27  来源:igfitidea点击:

如何检查Linux的Java时区。
使用tzupdater设置Java时区的步骤。
在RHEL或者CentOS Linux中为openjdk rpm更新tzdata。
更新tzdata-java rpm以更新Linux中Java的时区。
在Linux中使用tzupdater在Java时区中检查openjdk。
检查openjdk时区。
更新tzdata后是否需要重新启动

在本文中,我将通过示例向我们展示两种检查和设置Java时区(为openJDK更新tzdata)的方法

方法1:使用tzupdater为openJDK更新tzdata

为openJDK更新tzdata的第一种方法是使用ignize TZUpdater工具。
TZUpdater是Oracle的第三方工具,可以从Oracle官方页面下载。

什么是TZUpdater?

提供了TimeZone更新程序工具或者TZUpdater工具,使我们可以使用最新的时区数据来更新已安装的Java开发工具包(JDK)和Java运行时环境(JRE)软件,以适应不同国家的夏令时(DST)更改。

Oracle依靠可通过IANA时区数据库公开获得的时区数据。

在RHEL或者CentOS环境中,我们会找到tzdata rpm,它控制在系统级别应用的时区,而tzdata-java控制面向Java的应用程序(如openJDK,JRE等)的时区。

提示:

可以使用TZupdater工具,但不需要在RHEL/CentOS环境上设置Java时区,因为tzdata-java可以执行相同的更改,Red Hat也支持并正式发布了该更改。

但是仍然出于本文的目的,我将共享可用于在RHEL/CentOS/SLES或者具有类似源代码的发行版中设置Java时区的步骤。

安装TZUpdater

下载tzupdater存档后,可以使用以下步骤将其解压缩到Linux主机上的任何位置:

# unzip tzupdater-2_2_0.zip
Archive:  tzupdater-2_2_0.zip
   creating: tzupdater-2.2.0/
  inflating: tzupdater-2.2.0/README
  inflating: tzupdater-2.2.0/tzupdater.jar

检查Java TimeZone

在更新Java时区之前,我们应该检查现有的tzdata捆绑包,它是OpenJDK rpm的一部分。
使用以下语法:

# cd /root/tzupdater-2.2.0/
# java -jar tzupdater.jar -V | grep version
tzupdater version 2.2.0-b01
JRE tzdata version: tzdata2015i
tzupdater tool would update with tzdata version: tzdata2019b

所以目前我的OpenJDK包含tzdata2015i,考虑到撰写本文时最新的可用tzdata是2019b,它确实非常旧。

下载tzdata存档

要更新或者设置Java时区,我们接下来必须手动下载tzdata存档。

但是,如果我们只是想使用IANA上最新的可用tzdata存档来更新OpenJDK的tzdata,则无需下载任何存档。
我们只需要一个活动的Internet连接,tzupdater工具将下载最新的tzdata存档并将其安装在openJDK二进制文件中。

要下载不同版本的tzdata,可以查看IANA页面。

使用tzupdater设置Java时区

现在,由于我的系统已连接到Internet,并且希望应用最新的可用tzdata,因此我将执行以下命令来更新或者设置Java时区:

[root@node1 tzupdater-2.2.0]# java -jar tzupdater.jar -l
Using https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz as source for tzdata bundle.
Failed: java.lang.Exception: Failed while parsing file '/tmp/tz.tmp/asia' on line 1865 'Rule    Japan   1948   1951     -       Sep     Sat>=8  25:00   0       S'
java.lang.Exception: Failed while parsing file '/tmp/tz.tmp/asia' on line 1865 'Rule    Japan   1948    1951   -Sep     Sat>=8  25:00   0       S'
        at tools.tzdb.TzdbZoneRulesCompiler.parseFile(TzdbZoneRulesCompiler.java:377)
        at tools.tzdb.TzdbZoneRulesCompiler.compile(TzdbZoneRulesCompiler.java:191)
        at tools.tzdb.TzdbZoneRulesCompiler.(TzdbZoneRulesCompiler.java:307)
        at com.sun.tools.tzupdater.ExternalModule.compileToJSRBinary(ExternalModule.java:153)
        at com.sun.tools.tzupdater.TimezoneUpdater.run(TimezoneUpdater.java:230)
        at com.sun.tools.tzupdater.TimezoneUpdater.main(TimezoneUpdater.java:634)
Caused by: tools.tzdb.DateTimeException: Invalid value for SecondOfDay value: 90000
        at tools.tzdb.ChronoField.checkValidValue(ChronoField.java:173)
        at tools.tzdb.LocalTime.ofSecondOfDay(LocalTime.java:210)
        at tools.tzdb.TzdbZoneRulesCompiler.parseMonthDayTime(TzdbZoneRulesCompiler.java:475)
        at tools.tzdb.TzdbZoneRulesCompiler.parseRuleLine(TzdbZoneRulesCompiler.java:399)
        at tools.tzdb.TzdbZoneRulesCompiler.parseFile(TzdbZoneRulesCompiler.java:354)
        ... 5 more

其中

-l, --location 
                       Compile, test and update JRE timezone data from provided tzdata.tar.gz bundle
                       e.g -l https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz
                       Supported URL protocols : http://, https://, file://
                       If no URL link is provided, tool will use latest IANA tzdata bundle at:
                           https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz

tzdata2019b中的" asia"时区内容似乎存在一些问题。

如何修复解析文件'/tmp/tz.tmp/asia'时失败?

这必须由tzdata的开发团队解决,但对于我们而言,我们可以使用一种对我也有效的解决方法。
我检查了一些积压和历史记录,结果发现2016d之后发布的所有tzdata都包含针对亚洲时区文件的此问题。
因此我们可以从tzdata 2016d中获取asia时区文件并将其替换为tzdata2019b

警告:

这些步骤仅用于演示,除非我们知道后果,否则请勿在生产中进行。
与此更改一样,即使OpenJDK具有tzdata2019b,亚洲时区仍将使用tzdata2016d发布的旧数据。

从iana页面下载tzdata2016d在一个临时位置将其解压缩

# mkdir /tmp/tzdata2016d
# cp tzddata2016d.tar.gz /tmp/tzdata2016d
# cd /tmp/tzdata2016d
# tar -xzvf tzddata2016d.tar.gz

对tzdata2019b重复相同的步骤

# mkdir /tmp/tzdata2019b
# cp tzddata2019b.tar.gz /tmp/tzdata2016d
# cd /tmp/tzdata2019b
# tar -xzvf tzddata2019b.tar.gz

接下来将asia时区从2016d替换为2019b

node1:/tmp/tzdata2016d # cp asia ../tzdata2019b/asia
node1:/tmp/tzdata2016d # cd ../tzdata2019b/

接下来使用最新更改为2019b重新创建归档文件

node1:/tmp/tzdata2019b # tar -czvf ../tzdata2019b.tar.gz *

现在让我们重试使用tzupdater工具设置Java时区

node1:/tmp/tzupdater-2.2.0 # java -jar tzupdater.jar -l file:///tmp/tzdata2019b.tar.gz

因此,我们的解决方法起作用了,并且我们已经成功设置了Java时区。
使用file:///tmp/tzdata2019b.tar.gz作为tzdata包的源。

node1:/tmp/tzupdater-2.2.0 # java -jar tzupdater.jar -V
tzupdater version 2.2.0-b01
JRE tzdata version: tzdata2019b
tzupdater tool would update with tzdata version: tzdata2019b

重新启动Java应用程序以激活与时区相关的新更改

方法2:使用tzdata-java为openJDK更新tzdata

对于Red Hat/CentOS环境中的OracleJDK,我们也可以使用tzdata-javarpm,它也将在内部设置Java时区而不会带来任何麻烦。

说明:

在SLES环境中,我们会发现timezone-java,但这对作为OpenJDK一部分的tzdata版本没有影响,因此我们必须使用tzupdater

当前,我的系统运行的是tzdata rpm的2016e版本,如下所示:

# rpm -qa | grep tzdata
tzdata-java-2016e-3.el7.noarch
tzdata-2016e-3.el7.noarch

另外,如果我们使用tzupdater检查Java版本,则我的OpenJDK具有tzdata的2016e版本

[root@node1 tzupdater-2.2.0]# java -jar tzupdater.jar -V
tzupdater version 2.2.0-b01
JRE tzdata version: tzdata2016e
tzupdater tool would update with tzdata version: tzdata2019b

接下来,我们将通过从IANA数据库中手动下载rpm将tzdata rpm更新为2019a

说明:

在RHEL系统上,我们必须具有RHN的活动订阅,或者我们可以配置本地脱机存储库," yum"程序包管理器可以使用该本地存储库安装最新的tzdata rpm及其依赖项(如果有)。

[root@node1 tzupdater-2.2.0]# rpm -Uvh /root/tzdata-2019a-1.el7.noarch.rpm
warning: /root/tzdata-2019a-1.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID fd431d51: NOKEY
Preparing...                          ################################# [100%]
Updating/installing...
   1:tzdata-2019a-1.el7               ################################# [ 50%]
Cleaning up/removing...
   2:tzdata-2016e-3.el7               ################################# [100%]

并重新验证OpenJDK的tzdata版本,该版本保持不变,因为我们知道tzdata对OracleJDk的tzdata没有影响

[root@node1 tzupdater-2.2.0]# java -jar tzupdater.jar -V
tzupdater version 2.2.0-b01
JRE tzdata version: tzdata2016e
tzupdater tool would update with tzdata version: tzdata2019b

接下来我们将tzdata-java rpm更新为2019a

[root@node1 tzupdater-2.2.0]# rpm -Uvh /root/tzdata-java-2019a-1.el7.noarch.rpm
warning: /root/tzdata-java-2019a-1.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID fd431d51: NOKEY
Preparing...                          ################################# [100%]
Updating/installing...
   1:tzdata-java-2019a-1.el7          ################################# [ 50%]
Cleaning up/removing...
   2:tzdata-java-2016e-3.el7          ################################# [100%]

重新验证OracleJDK的tzdata,如我们所见,现在我们的OpenJDK Java也包含tzdata2019a

[root@node1 tzupdater-2.2.0]# java -jar tzupdater.jar -V
tzupdater version 2.2.0-b01
JRE tzdata version: tzdata2019a
tzupdater tool would update with tzdata version: tzdata2019b

重新启动Java应用程序以激活与时区相关的新更改

说明:

如我们所见,我们没有遇到方法一中的"亚洲"时区问题,这就是为什么我建议使用RHEL支持的rpm的原因,因为这里解决了这类问题。