GregorianCalendar年份设置不正确

时间:2015-04-25 23:12:24

标签: java

我对Java很新,我试图弄清楚GregorianCalendar的奇怪之处。似乎年份设置不正确(有时候。)

我做了以下测试功能,以说明问题:

   <rule ref="rulesets/java/design.xml/UseSingleton"/>

此函数接受Calendar对象,并生成如下所示的输出:

public static void testTime(Calendar c) {
   SimpleDateFormat sdf = 
         new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");       
   sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));

   System.out.println("---------------------------------");
   c.setTimeInMillis(0);
   Date d = c.getTime();
   System.out.println("Time 0: "  + sdf.format(d) + 
         " (" + d.getTime() + ")");

   c.set(Calendar.YEAR, 2000);
   d = c.getTime();
   System.out.println("Year 2000: "  + sdf.format(d) + 
         " (" + d.getTime() + ")");
   System.out.println("---------------------------------");
}

我从主要调用该函数3次;调用它的代码如下:

---------------------------------
Time 0: 1970/01/01 00:00:00 (0)
Year 2000: 2000/01/01 00:00:00 (946684800000)
---------------------------------

最后,这是输出:

   Calendar c = GregorianCalendar.getInstance();
   testTime(c);

   c.setTimeZone(TimeZone.getTimeZone("GMT+0"));
   testTime(c);

   c.setTimeZone(TimeZone.getTimeZone("America/Phoenix"));
   testTime(c);

正如您所看到的,当我使用从getInstance()获得的GregorianCalendar调用函数时,或者将时区设置为 “America / Phoenix”(我当地时区),年份输出为2001 。当我将时区设置为GMT时,年份(正确地说我相信)输出为 2000

有人可以向我解释一下我错过了什么吗?我想通过创建一个日历,使用我拥有的一些变量设置一些字段,并生成日期来使用日历。但是,我需要确保我回来的日期确实能够准确反映我的设定;我的单元测试让我有点疯狂,直到我意识到我的日期回来时与我输入的年份不符,所以我做了上面的代码测试。

编辑:要明确,我不关心由于时区造成的小偏移。我可以理解,并解释。由于时区而导致+ -24小时的时差是一回事;一年的时间差(2001年而不是2000年)是另一个时间差。

如果重要,这个Java运行在64位Linux机器上; java -showversion命令返回:

---------------------------------
Time 0: 1970/01/01 00:00:00 (0)
Year 2000: 2001/01/01 00:00:00 (978307200000)
---------------------------------
---------------------------------
Time 0: 1970/01/01 00:00:00 (0)
Year 2000: 2000/01/01 00:00:00 (946684800000)
---------------------------------
---------------------------------
Time 0: 1970/01/01 00:00:00 (0)
Year 2000: 2001/01/01 00:00:00 (978307200000)
---------------------------------

提前感谢您的帮助。我尽可能多地搜索了这里的电路板和互联网,找不到任何与我的问题相近的东西。

2 个答案:

答案 0 :(得分:1)

好的,我知道发生了什么。

当我设置年份时,它确实将年份设置为2000.然后它似乎使用它所具有的时区更新其余的内部字段。

这意味着当我将年份设置为2000时,它会设置该字段,并计算时间(包括时区)。前一次是1970年1月1日00:00:00。它将年份更新为2000年,将时间移回7小时(我的偏移量),时间为12月31日17:00 MST。这一年应该真的回到1999年,但它将在2000年离开,因为这是我设定的。因此产生的日期是2000年12月31日17:00。

当我打印日期时,我将SimpleDateFormat的时区设置为GMT。因此,它将时间向前移动7小时,至2001年1月1日00:00:00。

这确实令人困惑,但重复的测试表明它确实是这样做的。奇怪但真实。这里的教训(对我来说)是我应该设置输出对象的时区以匹配日历的时区。然后它会显示与我输入的日期相符的日期。

答案 1 :(得分:0)

当您尝试将新值与新YEAR重新分配给Date对象时,会出现问题。 这段代码:

    this.startDatePicker.MinDate = System.DateTime.Now;
    this.startDatePicker.Value = System.DateTime.Now;

不起作用。但是这一个:

c.setTimeInMillis(0);
       Date d = c.getTime();
       System.out.println("Time 0: "  + sdf.format(d) + 
             " (" + d.getTime() + ")");

适用于我的#34;没有时区&#34;情况下。

对于美国/菲尼克斯案,这就是问题所在:

c.setTimeInMillis(0);
       System.out.println("Time 0: "  + sdf.format(c.getTime()) + 
             " (" + c.getTime() + ")");

但您可以将其替换为

c.setTimeInMillis(0);

它会起作用。