Java日历:凌晨1点切换到标准时间(从DST开始)

时间:2012-11-07 22:48:33

标签: java calendar

我有一些代码使用Calendar.set()返回给定日期值的小时开头。我在2012年11月4日星期日(东部时区 - 美国东部时间到东部时间转换)遇到了以下问题:

public void testStartOfHourDST1() {

    Calendar cal = Calendar.getInstance();

    long time = 1352005200000L; // Nov 4, 2012, 1AM EDT
    cal.setTimeInMillis(time);

    cal.set(Calendar.MILLISECOND, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MINUTE, 0);

    System.out.println(new Date(time));
    System.out.println(new Date(cal.getTimeInMillis()));
    System.out.println(System.getProperty("java.version"));

    assertEquals(cal.getTimeInMillis(), time); // fails

    return;
}

输出继电器:

  

Sun Nov 04 01:00:00 EDT 2012

     

Sun Nov 04 01:00:00 EST 2012

     

1.6.0_35

也许这不是使用日历的正确方法,但在下一个小时(或前一个小时)运行相同的测试工作正常。这是JVM问题吗?

由于

2 个答案:

答案 0 :(得分:5)

这不是一个真正的问题,因为它是确定性的并且正在按照程序编程去做。如果您希望选择两个1ams中较早的一个,这是一个问题!

更改日历上的字段后,唯一的信息是“美国/东部时间凌晨1点”。那么,那天你的时区有两个1ams,它应该选择哪一个? OpenJDK的作者做出了一个决定,即当出现这种模糊性时,他们会在标准时间内将其解释为后者。此评论来自java.util.GregorianCalendar OpenJDK 6:

    // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
    //    can be in standard or DST.  Both are valid representations (the rep
    //    jumps from 1:59:59 DST to 1:00:00 Std).
    //    Again, we assume standard time.

如果您打印出数字的实际值,您会看到cal.getTimeInMillis()实际上已经从time的值改变了一个小时。

答案 1 :(得分:0)

获取正确的时区非常重要。例如,我确信您知道系统当前时间(以毫秒为单位)是从1970年1月1日午夜开始测量的。这是有据可查的。 Date构造函数JavaDoc说:

  

公开日期(漫长日期)

     

分配Date对象并初始化它以表示指定的对象   自标准基准时间以来称为“。”的毫秒数   时代“,即1970年1月1日,格林尼治标准时间00:00:00。

这很好,但是这个程序的输出起初有点难以理解:

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

public class Demo {
    public static void main(String[] args) {
        TimeZone tz = TimeZone.getTimeZone("Europe/London");
        Date d = new Date(-3600000);

        SimpleDateFormat df = new SimpleDateFormat("MMMM dd, yyyy HH:mm:ss.SSS z");
        df.setTimeZone(tz);
        System.out.println(String.format("%8dms -> %s",
                    Long.valueOf(d.getTime()) ,df.format(d)));

        d.setTime(0);
        System.out.println(String.format("%8dms -> %s",
                    Long.valueOf(d.getTime()) ,df.format(d)));
   }
}

输出结果为:

-3600000ms -> January 01, 1970 00:00:00.000 GMT
       0ms -> January 01, 1970 01:00:00.000 GMT

正如你所看到的,这个时代显然已经被移走了一个小时!

除非不是。如果您明确使用“GMT”时区,一切都很好。 “欧洲/伦敦”时区就像那样棘手。

使用日历时,请了解您正在使用或被捕获的时区。