测试环境:java version "1.7.0_09"OS:windows 7
测试步骤:1.在控制面板 -> 区域语言 -> 位置 -> 选择“智利”2.右下角,调整时间-> 更改日期和时间设置 -> 选择时区 -4 圣地亚哥3.运行如下测试代码。
测试代码:package test;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;public class Test {
public static void main(String[] args) {
TimeZone tz = TimeZone.getDefault(); Long nowUTC = System.currentTimeMillis();
Date nowLocal = new Date(nowUTC); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(tz);// 打印跳变规则
System.out.println(sdf.format(nowLocal));// 打印JDK处理后的本地时间
}
}
打印timezone:sun.util.calendar.ZoneInfo[id="America/Santiago",offset=-14400000,dstSavings=3600000,useDaylight=true,transitions=159,lastRule=java.util.SimpleTimeZone[id=America/Santiago,offset=-14400000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=9,startDay=9,startDayOfWeek=1,startTime=14400000,startTimeMode=2,  endMode=3,  endMonth=2,  endDay=9,  endDayOfWeek=1,  endTime=10800000,  endTimeMode=2]]
分析跳变规则(具体参数含义请google):夏令时跳入:10月9日后的第一个周日(包括当天),UTC的4:00:00由于跳入夏令时前,时区偏移量是offset = -4所以,UTC时间转为本地时间后,跳入夏令时的本地时间是:2012.10.14 00:00:00=====================夏令时跳出:3月9日后的第一个周日(包括当天),UTC的3:00:00由于跳出夏令时前,时区偏移量是offset + dstSavings = -3所以,UTC时间转为本地时间后,跳出夏令时的本地时间是:2012.3.11 00:00:00=====================理论夏令时跳入时间:2012.10.14 00:00:00理论夏令时跳出时间:2012.3.11 00:00:00
实际结果:OS右下角更改时间,到2012.10.13 22:59:55 左右      运行测试代码:2012-10-13 23:59:55       5秒后再运行: 2012-10-14 00:00:00 (理论上,应该跳变为2012-10-14 01:00:00)ps:(不知为何,JDK的时间,比OS快了1小时,所以想要JDK的这个时间,必须调OS为22点)=====================OS右下角更改时间,到2012-03-10 23:59:55 左右      运行测试代码:2012-03-10 23:59:55      5秒后再运行: 2012-03-11 00:00:00 (理论上,应该跳变为2012-03-10 23:00:00)疑问:JDK BUG? 根据打印出来的规则推算出跳变时间,可实际采用的却不是这套跳变规则

解决方案 »

  1.   

    新发现:耶路撒冷 夏令时跳出 的日期,与JDK打印出来的TimeZone规则不一致。
      

  2.   


    现在的问题是:根据JDK打印出来的跳变规则,可以推算出如下时间跳变:
    理论夏令时跳入时间:2012.10.14 00:00:00
    理论夏令时跳出时间:2012.3.11 00:00:00
    可构造时间到上面两个时间点,却没有跳变
      

  3.   

    我觉得这个与JVM没什么关系,JVM是去取得系统时间,然后输出,例如下面的例子,就可以看到JVM的时间是取自系统,JVM没有自己的一套时间系统:在程序运行的过程中,我不停的修改系统的时间,程序同时把新修改的时间读取并输出
    import java.util.Date;public class Hello {
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 20; ++i) {
                Date date = new Date();
                System.out.println(date);            Thread.sleep(2000);
            }
        }
    }Mon Dec 10 19:44:50 CST 2012
    Mon Dec 10 19:44:52 CST 2012
    Mon Dec 10 19:44:54 CST 2012
    Thu Dec 20 19:44:55 CST 2012
    Thu Dec 20 19:44:57 CST 2012
    Thu Dec 20 19:44:59 CST 2012
    Thu Dec 20 19:45:01 CST 2012
    Thu Dec 20 19:45:03 CST 2012
    Sun Dec 16 19:45:04 CST 2012
    Sun Dec 16 19:45:06 CST 2012
    Sat Dec 15 19:45:06 CST 2012
    Sat Dec 15 19:45:08 CST 2012
    Mon Dec 03 19:45:09 CST 2012
    Mon Dec 03 19:45:11 CST 2012
    Mon Dec 10 19:45:18 CST 2012
    Mon Dec 10 19:45:20 CST 2012
    Mon Dec 10 19:45:22 CST 2012
    Mon Dec 10 19:45:24 CST 2012
    Mon Dec 10 19:45:26 CST 2012
    Mon Dec 10 19:45:28 CST 2012
      

  4.   

    修改的是日期中的天
    Thu Dec 20 19:45:03 CST 2012 // 20是天
    Sun Dec 16 19:45:04 CST 2012 // 16是天
    Sun Dec 16 19:45:06 CST 2012
    Sat Dec 15 19:45:06 CST 2012 // 15是天
      

  5.   


    ps:(不知为何,JDK的时间,比OS快了1小时,所以想要JDK的这个时间,必须调OS为22点)

    你自己不是已经发现了吗...jvm已经计算了夏令时,相差了1个小时
    估计系统的显示时间应该是根据你设置的时区进行增量吧,系统也不可能在夏令时中调整时钟,肯定也是以偏移计算显示时间的,这个你要去查MSDN的说明了
      

  6.   

    调到我说的圣地亚哥时区和理论夏令时时间试试。
    而且使用java version "1.7.0_09"
    我想证明的是:JVM理论夏令时规则 和 JVM实际测试的结果不一致不要去管操作系统的时间,操作系统的时间怎么跳变由操作系统来做的
    你之所以打印的结果和操作系统一致,是因为根本没发生夏令时跳变我的理解如下:UTC时间 --> 操作系统的夏令时规则 --> 显示到操作系统上的挂钟时间
    UTC时间 --> JVM的夏令时规则 --> 通过打印获得挂钟时间操作系统和JVM,都会根据各国政府的夏令时政策,来发布夏令时补丁
    有如下关系:挂钟时间 = UTC时间 + 偏移量 + 夏令时java的new Date(),实际上是隐藏了这个计算过程的
      

  7.   

    JDK和OS都有时区规则,你这种情况应该是两个时区规则版本不一致。