转载连接: https://my.oschina.net/huawu/blog/4646

昨天发现跑在Linux上的java程序获取的默认时区有问题。

由于我所用Linux的时区由/etc/localtime所指的文件(如果环境变量TZ不存在时):
[xx:~]> ls -l /etc/localtime
lrwxrwxrwx 1 root root 18 Jun 21 2008 /etc/localtime -> /var/etc/localtime
[xx:~]> ls -l /var/etc/localtime
lrwxrwxrwx 1 root root 30 May 14 09:46 /var/etc/localtime -> /usr/share/zoneinfo/US/Eastern

开始时,我以为应该是和/etc/localtime指向的时区一样的,接着才发现原来java在没有TZ环境变量时取的是 /etc/sysconfig/clock

中的时时区。 Sun上面有和我这种情况相关的bug - Default timezone is incorrectly set occasionally on Linux**(http://bugs.sun.com/view_bug.do?bug_id=6456628)**, 里面描述了java vm取的默认timezone的算法:

1)如有环境变量 TZ设置,则用TZ中设置的时区

2)在 /etc/sysconfig/clock文件中找 “ZONE”的值

3)如何2)都没,就用/etc/localtime 和 /usr/share/zoneinfo 下的时区文件进行匹配,如找到匹配的,就返回对应的路径和文件名。

下面是我的测试:

java测试程序(来自:http://www.minaret.biz/tips/timezone.html)

import java.util.Date;
import java.util.TimeZone;public class TimeTest {public static void main(String args[]) {long time = System.currentTimeMillis();String millis = Long.toString(time);Date date = new Date(time);System.out.println("Current time in milliseconds = " + millis + " => " + date.toString());System.out.println("Current time zone: " + TimeZone.getDefault().getID());}
}

查看本地时区设置:

[xx:~]> echo $TZ

(TZ 环境变量没设置)
[xx:~]> ls -l /var/etc/localtime
lrwxrwxrwx 1 root root 30 May 14 02:24 /var/etc/localtime -> /usr/share/zoneinfo/US/Arizona

[xx:~]>date
Fri May 14 02:30:05 MST 2010

date 命令显示的时间 和 /var/etc/localtime 指向的时间一致

查看/etc/sysconfig/clock中的时区设置(Redhat Linux)
[xx:~]> cat /etc/sysconfig/clock
ZONE=”America/New_York”
UTC=false
ARC=false

[xx:~]> java TimeTest
Current time in milliseconds = 1273829564349 => Fri May 14 05:32:44 EDT 2010
Current time zone: America/New_York
Current time zone display: Eastern Standard Time
[xx:~]>

TimeTest运行结果显示,java vm取得的的默认时区和 /etc/sysconfig/clock 中的设置一样。让我们来验证一下:
1)修改/etc/sysconfig/clock:
[xx:~]> vim /etc/sysconfig/clock
ZONE=”US/Central”
UTC=false
ARC=false
2)再运行 TimeTest
[xx:~]> java TimeTest
Current time in milliseconds = 1273829718269 => Fri May 14 04:35:18 CDT 2010
Current time zone: US/Central
Current time zone display: Central Standard Time

修改/var/etc/localtime 指向时区
先看看date显示:
[xx:~]> date
Fri May 14 02:36:37 MST 2010
[xx:~]> sudo ln -sf /usr/share/zoneinfo/US/Central /var/etc/localtime
查看date命令结果的变化
[xx:~]> date
Fri May 14 04:37:41 CDT 2010
可以到时间和时区自动变了

好,再看另外一种情况:当 TZ 这个环境变量存在并有设置时

首先看看TZ的值为空时,date命令结果的变化
[xx:~]> export TZ=
[xx:~]> date
Fri May 14 09:41:04 UTC 2010

时间变了,且时区显示是UTC(Universial Time Coordination).

也看看TimeTest的运行结果:
[xx:~]> java TimeTest
Current time in milliseconds = 1273830175690 => Fri May 14 09:42:55 GMT 2010
Current time zone: GMT
Current time zone display: Greenwich Mean Time
[xx:~]>

可以看出,java vm 默认时区是GMT。

给TZ赋某个时区:

[xx:~]> export TZ=”US/Central”
[xx:~]> date

Fri May 14 04:44:40 CDT 2010

date的输出跟着 TZ 变量马上调整过来

运行TimeTest
[xx:~]> java TimeTest
Current time in milliseconds = 1273830328966 => Fri May 14 04:45:28 CDT 2010
Current time zone: US/Central
Current time zone display: Central Standard Time

TimeTest 取得和TZ一样的时区

[xx:~]> sudo ln -sf /usr/share/zoneinfo/US/Eastern /var/etc/localtime
[xx:~]> date
Fri May 14 04:46:16 CDT 201

[xx:~]> export TZ=”US/Eastern”
[xx:~]> date
Fri May 14 05:47:58 EDT 2010

参考资料:

1.Default timezone is incorrectly set occasionally on Linux
http://bugs.sun.com/view_bug.do?bug_id=6456628

  1. 如何设置Linux时间
    http://www.hypexr.org/linux_date_time_help.php
  2. 解决java default Timezone 问题的方法
    http://www.minaret.biz/tips/timezone.html

————-补充:
1.jre时区支持查看目录:
java.home/jre/lib/zi
2.linux时区支持查看目录:
ls -l /usr/share/zoneinfo
单个java应用,可以在在启动时候设置时区:

java -Duser.timezone=GMT+08 ...jar

3.liunx系统时区设置详细连接:
http://coolnull.com/235.html

4.没有权限的情况下,如何实现改动
1)Java启动时候增加
-Duser.timezone=对应时区
2)linux修改:

 export TZ='Asia/Jakarta'    ----测试结果单引号有效果,双引号有问题echo $TZ

可以通过命令tzselect 选择对应时区,显示正确的格式


遇到问题:

$ echo $TZ$ ls -l /etc/localtimelrwxrwxrwx 1 root root 33 Oct 28  2016 /etc/localtime ->  /usr/share/zoneinfo/Asia/Shanghai
$ cat /etc/sysconfig/clock ZONE="Asia/Jakarta"UTC=falseARC=false  

结果启动时候使用的是/Asia/Shanghai时区,和上面的时区处理顺序有差异!(暂时没有权限修改测试,待解决)

/etc/sysconfig/clock
配置文件里面支持 UTC,ARC,SRM,ZONE 这几个配置选项。

UTC – 指定 BIOS 中保存的时间是否是 GMT/UTC 时间,true 或 yes 表示 BIOS 里面保存的时间是 UTC
时间,false 或 no 表示 BIOS 里面保存的时间是本地时间。 ZONE – 指定时区,ZONE
的值是一个文件的相对路径名,这个文件是相对 /usr/share/zoneinfo 目录下的一个时区文件。比如 ZONE
的值可以是:“Asia/Shanghai”, “US/Pacific”, “UTC” 等(默认为ZONE=”Etc/UTC”)。 ARC –
这个选项一般配置 false 或 no,在一些特殊硬件下才配置该选项为 true 或 yes。 SRM – 同 ARC,该选项一般配置
false 或 no,在一下特殊硬件下才配置该选项为 true 或 yes


遇到比较奇葩的情况:
美国服务器:
查看系统时区为:

 date -RTue, 11 Jul 2017 18:59:13 +0700
$echo $TZ$ cat /etc/timezone
Asia/Shanghai$cat /etc/sysconfig/clock
ZONE="Asia/Jakarta"
UTC=false
ARC=false

如果java启动的时候不设置时区,默认为时区为UTC+07的时区
如果java启动时候配置为:
java -server -Duser.timezone=UTC+07
则有效果,时区为+7时区
如果java启动时候配置为:
java -server -Duser.timezone=UTC+06
则无效果,时区还是为+7时区
如果java启动时候配置为:
java -server -Duser.timezone=UTC+08
则有效果,但是时区是为+0时区
如果java启动时候配置为:
java -server -Duser.timezone=GMT+06
则有效果,时区还是为+6时区


查询了JDK底层代码:
又对GMT 格式的专门解析方法:

 static final String         GMT_ID        = "GMT"
private static TimeZone getTimeZone(String ID, boolean fallback) {TimeZone tz = ZoneInfo.getTimeZone(ID);if (tz == null) {tz = parseCustomTimeZone(ID);if (tz == null && fallback) {tz = new ZoneInfo(GMT_ID, 0);}}return tz;}private static final TimeZone parseCustomTimeZone(String id) {int length;// Error if the length of id isn't long enough or id doesn't// start with "GMT".if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||id.indexOf(GMT_ID) != 0) {return null;}ZoneInfo zi;// First, we try to find it in the cache with the given// id. Even the id is not normalized, the returned ZoneInfo// should have its normalized id.zi = ZoneInfoFile.getZoneInfo(id);if (zi != null) {return zi;}int index = GMT_ID_LENGTH;boolean negative = false;char c = id.charAt(index++);if (c == '-') {negative = true;} else if (c != '+') {return null;}int hours = 0;int num = 0;int countDelim = 0;int len = 0;while (index < length) {c = id.charAt(index++);if (c == ':') {if (countDelim > 0) {return null;}if (len > 2) {return null;}hours = num;countDelim++;num = 0;len = 0;continue;}if (c < '0' || c > '9') {return null;}num = num * 10 + (c - '0');len++;}if (index != length) {return null;}if (countDelim == 0) {if (len <= 2) {hours = num;num = 0;} else {hours = num / 100;num %= 100;}} else {if (len != 2) {return null;}}if (hours > 23 || num > 59) {return null;}int gmtOffset =  (hours * 60 + num) * 60 * 1000;if (gmtOffset == 0) {zi = ZoneInfoFile.getZoneInfo(GMT_ID);if (negative) {zi.setID("GMT-00:00");} else {zi.setID("GMT+00:00");}} else {zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);}return zi;}

Java TimeZone 和 Linux TimeZone问题相关推荐

  1. Linux TimeZone设置

    最近遇到一个有关timezone的问题:有些application需要环境变量TZ,可是我们刚刚装好的RHEL没有设置TZ,而我又没有root权限去改,查了半天资料,发现所有对timezone的改动都 ...

  2. 第90节:Java中的Linux基础

    第90节:Java中的Linux基础 linux是装载虚拟机上面的: JDK依赖包: yum install glibc.i686MYSQL依赖包: yum -y install libaio.so. ...

  3. 在linux怎样运行java,怎么在linux运行java

    怎么在linux运行java [2021-02-01 00:44:14]  简介: php去除nbsp的方法:首先创建一个PHP代码示例文件:然后通过"preg_replace(" ...

  4. linux收缩java位置,找到linux中当前java的安装位置

    先看java -version $java version "1.8.0_111" Java(TM) SE Runtime Environment (build 1.8.0_111 ...

  5. linux钟java运行命令,在java中运行linux命令

    我想在java中运行"ls"命令,我的代码是- 注意: - 我正在使用WINDOWS.在java中运行linux命令 import java.io.IOException; pub ...

  6. java查看日志命令_[Java教程]【Linux】linux查看日志文件内容命令tail、cat、tac、head、echo...

    [Java教程][Linux]linux查看日志文件内容命令tail.cat.tac.head.echo 0 2017-11-14 12:00:29 linux查看日志文件内容命令tail.cat.t ...

  7. java jcsh执行linux命令,java jcsh执行linux命令

    java jcsh执行linux命令 [2021-02-03 01:26:29]  简介: php去除nbsp的方法:首先创建一个PHP代码示例文件:然后通过"preg_replace(&q ...

  8. 你的java程序有没有内存泄露,java进程在linux系统中rss计算方式是什么样的?

    java进程在linux系统中rss计算方式如下: RSS = Heap size + MetaSpace + OffHeap size 其中OffHeap由线程堆栈,直接缓冲区,映射文件(库和jar ...

  9. linux java -cp lt; .txt_补交 20155202 蓝墨云班课 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能...

    蓝墨云班课 编写MyCP.java 要求: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX ...

最新文章

  1. Jmeter Md5加密操作之-------BeanShell PreProcessor
  2. Hibernate一对多(注解)
  3. [Java] grails 安装手记
  4. 产品经理在工作中如何进行沟通
  5. matlab重置矩阵大小resize,JS resize事件:窗口重置
  6. 【渝粤教育】10259k2_经济学基础_21秋考试
  7. Pandas-层次化索引
  8. Effective C++ ——设计与声明
  9. Spring MVC请求处理流程分析
  10. js中的onscroll的用法
  11. networking常用命令
  12. ButterKnife 8.6.0 使用
  13. 新基建安全怎么做?看看这场院士领衔的高峰对话
  14. android设置背景渐变色,Android背景渐变色(shape,gradient)
  15. Android编译中m、mm、mmm的区别
  16. 用计算机开3次方,android系统计算器开3次方
  17. 京东云引擎:免费好用的web应用托管平台
  18. 医疗器械行业按下“加速键”,华瑭医疗的总代生意却并不好做
  19. Shopee聊聊客服工作日常
  20. 2013年5月中国数码相机市场分析报告

热门文章

  1. 在中国,办事吃饭是常事,但是这样的饭局往往是不好应付的,诸多的潜规则等待你去体味。为了不出丑,呵呵,还是提早学习下为好。
  2. c语言如何使一行抹去,c语言,clrscr();怎么清除指定的内容,不是页面都清除掉。比如第一行是标题,我只想清除第二行...
  3. 将bolg同时部署到Github和coding
  4. opencv-python阈值分割
  5. Java IO流大闯关--IO流的常用实现类
  6. MySQL——基础篇
  7. 三菱FX3U与4台三菱变频器专用指令通讯案例 功能:采用三菱FX3U PLC与4台三菱变频器E740进行通讯
  8. java统计用户网页停留时间,前端js计算用户在网页的停留时间和用户是否在点击浏览的时间...
  9. MSSQL 数据库被标记为SUSPECT状态,如何恢复?
  10. 企业公关形象传播及效果评估