最近我在自己的树莓派上使用docker跑java程序,发现几个关于时区时间的设置问题,记录如下
数据库中的时间和编码都不正确,
我检查发现是我的jdbcurl中没有配置不对,于是我把jdbcUrl改成如下:
jdbc:mysql://localhost:3306/daily?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
修改之后发现数据库中的乱码正常了,但是时间还是不对。
镜像中时区不对
我使用docker exec -it 容器名 /bin/bash
命令进入容器中,使用date -R
命令查看时间发现时间相差八小时, 这应该是经典的时区设置不对了。
于是我进行大量百度,发现各种解决办法, 于是我挑了一个看起来靠谱的方法。
docker run -v /etc/localtime:/etc/localtime -p 8443:8443 镜像名称:v1
原理是:百度的原因都是容器中时区文件/etc/localtime
不存在或者设置不对, 我想着既然宿主机的时区是对的, 我就把宿主机的时区设置进容器中,这样容器不就和宿主机一样的时区了。
运行起来后发现容器中的时间
date -R
命令查看后是正确的, 于是我以为时间问题已经解决,便没有在关注时间了
再次发现时区不对
我的程序运行一段时间后,我查看数据库发现时间还是不对,我就十分郁闷。 我再次进入容器查看时区发现是正确的, 也就是我的java程序在容器中的时区不正确,于是我再次开启百度,发现这篇好文章 : Java程序与操作系统时区不一致问题的处理 这篇文章详细讲明白了java程序如何获取时区信息的。 此处我在摘抄下文章中关于获取时区的描述:
首先我们来看下Java程序是怎样取得时区信息的。通过Oracle的官方文档,我们可以知道其默认时区的获取方式:
- Use the user.timezone property value as the default time zone ID if it’s available.
- Detect the platform time zone ID. The source of the platform time zone and ID mapping may vary with implementation.
- Use GMT as the last resort if the given or detected time zone ID is unknown.
从上面可以知道java显示通过用户的配置 user.timezone
作为时区信息的, 如果user.timezone
没有配置就会获取运行平台(linux)的配置的Zone ID作为时区信息的,如果最后程序还是没有获取到时区信息 就会使用GMT时间作为最后的时区信息(就是使用GMT+0)作为最后的时区信息。
这篇文章中推荐解决办法是在增加-Duser.timezone=Asia/Shanghai
启动参数来解决问题。 这是一种方案。
但是我还是没有弄明白我之前的解决方案为何不行, 因为我的解决方法应该符合java获取时区的第二种方式的。 最后我还是在这篇文章中找到原因,文章中说的centos的系统的/etc/localtime
文件是使用软连接的方式指向 /usr/share/zoneinfo/Asia/Shanghai
的。所以centos的时区就是Asia/Shanghai
。 于是我就怀疑我的宿主机(ubuntu)也是使用的软连接的方式, 于是我运行命令:
ubuntu@ubuntu ~ % ls -li /etc/localtime
1346 lrwxrwxrwx 1 root root 33 May 21 06:21 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
发现确实如此啊, 我使用docker的-v 挂载的/etc/localtime 实际上只是宿主机的一个软连接,所以容器中得时区不对
解决办法: 将真实的宿主机的时区文件挂载到容器的时区文件中就可以解决时区不对的问题
下面是我的Dockerfile文件和启动命令
FROM adoptopenjdk:11-jre-hotspot
# 设置容器的时区
RUN mkdir /opt/app
ADD xSpider-1.0-SNAPSHOT /opt/app/spider
EXPOSE 8443
VOLUME /log
VOLUME /home/ubuntu/mzitu
# 挂载时区的目录
VOLUME /usr/share/zoneinfo
# 设置时区为上海
ENV TZ=Asia/Shanghai
# 设置时区信息
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 启动程序的脚本
ENTRYPOINT ["/opt/app/spider/bin/xSpider"]
启动命令:
sudo docker run -d -v /home/ubuntu/projects/spider/log:/log -v /media/newsmy/mzi:/home/ubuntu/mzitu -v /usr/share/zoneinfo:/usr/share/zoneinfo --name xspider -p 8443:8443 xspider:v1
问题解决