说说Java中的TimeZone夏令时问题

在Linux上使用system-config-date工具来设置了一个TimeZone之后(设置的结果会被记录在/etc/sysconfig/clock文件中),在进出夏令时的时候Java中取的时间不能跟着夏令时的时钟变化,从而导致Java中的系统时间出现混乱。

我们写了一个小程序用来获取当前机器上的TimeZone信息,以及打印一些时间看看进/出夏令时的时候时间的变化。

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

public class TimeZoneTest {
    public static void main(String[] args) {
        TimeZone tz = TimeZone.getDefault();
        System.out.println("tz: " + tz);

        int offset = tz.getRawOffset();
        System.out.println("raw offset: " + offset);

        int dstSavings = tz.getDSTSavings();
        System.out.println("dstSavings: " + dstSavings);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        while(true) {
            Calendar cal = Calendar.getInstance();
            String msg = "[" + sdf.format(cal.getTime()) + "] " + cal.getTime();
            msg += ", offset: " + TimeZone.getDefault().getOffset(cal.getTimeInMillis());
            System.out.println(msg);

            try {
                Thread.sleep(60 * 1000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
}

下面两个正确的Case是在设置了TimeZone为“America/Los_Angeles”的情况下运行的结果

Case 1: 设置系统时间为2014-03-09 01:59:00 AM

tz: sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
raw offset: -28800000
dstSavings: 3600000
[2014-03-09 01:59:03] Sun Mar 09 01:59:03 PST 2014, offset: -28800000
[2014-03-09 03:00:03] Sun Mar 09 03:00:03 PDT 2014, offset: -25200000
[2014-03-09 03:01:03] Sun Mar 09 03:01:03 PDT 2014, offset: -25200000

Case 2: 设置系统时间为2014-11-02 12:59:00 AM

tz: sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
raw offset: -28800000
dstSavings: 3600000
[2014-11-02 01:59:32] Sun Nov 02 01:59:32 PDT 2014, offset: -25200000
[2014-11-02 01:00:32] Sun Nov 02 01:00:32 PST 2014, offset: -28800000
[2014-11-02 01:01:32] Sun Nov 02 01:01:32 PST 2014, offset: -28800000

Case 3: 设置TimeZone为“America/North_Dakota/Center”,设置系统时间为2014-03-09 01:59:00 AM,再运行上面的程序发现

tz: sun.util.calendar.ZoneInfo[id="GMT-06:00",offset=-21600000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
raw offset: -21600000
dstSavings: 0
[2014-03-09 01:59:12] Sun Mar 09 01:59:12 GMT-06:00 2014, offset: -21600000, loader start date: Sun Mar 09 01:59:00 GMT-06:00 2014
[2014-03-09 02:00:12] Sun Mar 09 02:00:12 GMT-06:00 2014, offset: -21600000, loader start date: Sun Mar 09 02:00:00 GMT-06:00 2014
[2014-03-09 02:01:12] Sun Mar 09 02:01:12 GMT-06:00 2014, offset: -21600000, loader start date: Sun Mar 09 02:01:00 GMT-06:00 2014

从结果中可以看到TimeZone ID=GMT-06:00, dstSavings=0,并且在时间从1:59变到2:00的时候时间并没有向后调整到3:00 ,这说明Java没有找到对应的时区信息(也许这是Java的一个bug),所以Java就不知道当前这个时区是不是使用了夏令时,所以最终导致取得的时间不对。

对于这类问题,可以通过下面两个方法解决

1. 使用TZ环境变量,然后在运行Java程序

$ export TZ=America/North_Dakota/Center
$ java TimeZoneTest

2. 使用-Duser.timezone=America/North_Dakota/Center作为Java虚拟机的系统参数

java -Duser.timezone=America/North_Dakota/Center TimeZoneTest

另外,可以通过下面的一些命令查看系统的timezone信息

cat /usr/share/zoneinfo/zone.tab
zdump /usr/share/zoneinfo/*
zdump -v /usr/share/zoneinfo/America/New_York 查看夏令时时间变化点
zdump -v /etc/localtime
tz_convert /usr/share/zoneinfo/
sudo cat /etc/sysconfig/clock

说说Java中的TimeZone夏令时问题

时间: 2024-11-05 17:18:10

说说Java中的TimeZone夏令时问题的相关文章

Java中的夏令时问题

因为在用C#的时候被夏令时,由于不知道被坑过一回,所以这次将在java中的时区转换信息做一下记录,很简单 SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); inputFormat.setTimeZone(TimeZ

详解Java中的时区类TimeZone的用法

一.TimeZone 简介 TimeZone 表示时区偏移量,也可以计算夏令时. 在操作 Date, Calendar等表示日期/时间的对象时,经常会用到TimeZone:因为不同的时区,时间不同. 下面说说TimeZone对象的 2种常用创建方式.1.获取默认的TimeZone对象使用方法: TimeZone tz = TimeZone.getDefault() 2.使用 getTimeZone(String id) 方法获取TimeZone对象使用方法: // 获取 "GMT+08:00&q

Java中的时间和日期(上)

自从JDK 1.0开始,Java就提供了Date来处理时间和日期,作为老古董自然有很多东西是过时的.然后出现了Calendar来解决了很多问题,但是Calendar使用比较复杂,并且有些反人类的地方.直到Java 8的出现,它吸收了Joda-Time库的经验,使得Java处理时间和日期变得比较"人性化"了.本篇就来谈谈Java中的Date.Calendar,以及SimpleDateFormat的使用.下一篇再对比一下Java 8中的日期处理. 古老的Date 查看一下Date类的源码,

java中获取系统属性以及环境变量

java中获取系统属性以及环境变量 System.getEnv()和System.getProperties()的差别 从概念上讲,系统属性 和环境变量 都是名称与值之间的映射.两种机制都能用来将用户定义的信息传递给 Java 进程.环境变量产生很多其它的全局效应,由于它们不仅对Java 子进程可见,并且对于定义它们的进程的全部子进程都是可见的.在不同的操作系统上,它们的语义有细微的区别,比方,不区分大写和小写.由于这些原因,环境变量更可能有意料不到的副作用.最好在可能的地方使用系统属性.环境变

Java中日期的总结

#####1.日期 日期:主要使用的是*java.util.Date* 以及*java.sql.Date* , sql中的Date是util中Date的子类,关系如下,但是如果直接转换的话会出现Cast转换错误. - java.lang.Object - java.util.Date - java.sql.Date 之间的转换可以通过如: ```javajava.util.Date utildate=new java.util.Date(System.getCurrentTime());java

转- 关于时间,日期,星期,月份的算法(Java中Calendar的使用方法)

package cn.outofmemory.codes.Date; import java.util.Calendar; import java.util.Date; public class CalendarDemo { public static void main(String[] args) { Calendar calendar=Calendar.getInstance(); calendar.setTime(new Date()); System.out.println("现在时间

关于时间,日期,星期,月份的算法(Java中Calendar的使用方法)(一)

package cn.outofmemory.codes.Date; import java.util.Calendar; import java.util.Date; public class CalendarDemo { public static void main(String[] args) { Calendar calendar=Calendar.getInstance(); calendar.setTime(new Date()); System.out.println("现在时间

详解Java中格式化日期的DateFormat与SimpleDateFormat类

DateFormat其本身是一个抽象类,SimpleDateFormat 类是DateFormat类的子类,一般情况下来讲DateFormat类很少会直接使用,而都使用SimpleDateFormat类完成,下面我们具体来看一下两个类的用法: DateFormat1. DateFormat 介绍DateFormat 的作用是 格式化并解析“日期/时间”.实际上,它是Date的格式化工具,它能帮助我们格式化Date,进而将Date转换成我们想要的String字符串供我们使用不过DateFormat

【转】Java中本地时间的获取方法--不错

原文网址:http://highforest.blog.51cto.com/125539/842496/ 熟悉Oracle数据库的人,应该知道:select to_char(sysdate,'yyyy-mm-dd' hh24:mi:ss)from dual将会查询到怎样的结果, 不错,就是类似2012-04-23 20:43:57这样的一个19位的字符串.那么在Java中怎么得到这样一个字符串呢?网上给出了不少类似的例子,但屡试不爽.只好仔细研究Java 的API文档,终于找到了解决办法: im