Java TimeZone 和 Linux TimeZone问题
来源:互联网 发布:谢娜主持的网络综艺 编辑:程序博客网 时间:2024/05/22 23:16
转载连接: 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
- 如何设置Linux时间
http://www.hypexr.org/linux_date_time_help.php - 解决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/localtime lrwxrwxrwx 1 root root 33 Oct 28 2016 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai$ cat /etc/sysconfig/clock ZONE="Asia/Jakarta" UTC=false ARC=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 -R Tue, 11 Jul 2017 18:59:13 +0700
$echo $TZ$ cat /etc/timezoneAsia/Shanghai$cat /etc/sysconfig/clockZONE="Asia/Jakarta"UTC=falseARC=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问题
- TimeZone
- Timezone
- timezone
- TimeZone
- timezone
- timezone
- timezone
- timezone
- Java TimeZone
- 说说Java中的TimeZone夏令时问题
- Java Timezone 与 Linux时间不一致
- SQL SERVER和ORACLE 的TimeZone问题
- java时区-DateFormat和TimeZone关…
- PHP TimeZone 的问题
- PHP timezone问题
- PHP TimeZone 的问题
- EBS TimeZone问题
- Thymeleaf 标准表达式语法
- Android 黑屏收不到消息
- 屏蔽安卓7.0屏幕显示大小可调的问题
- DOS特殊字符转义
- Android L集成新特性之恢复出厂设置保护之如何实现,类似苹果ID的远程控制功能
- Java TimeZone 和 Linux TimeZone问题
- Android 记住密码功能
- C++语言例题
- 研究生期间读书目录
- UE4 自带的一些模块
- 按周显示的日历和按月显示的日历,你需要吗
- Windows7+WDK+VS2010+VisualDDK驱动开发环境搭建
- 为何编程如此之难?
- java动态创建xml文件