【问题标题】:Weird behavior of Calendar日历的奇怪行为
【发布时间】:2015-08-12 02:14:57
【问题描述】:

我正面临java.util.Calendar 的奇怪行为。

问题是,当我在两者之间添加一个方法调用 Calendar#getTime() 时,我得到正确的结果,但是当我直接获得一周的 Dates 而没有调用 Calendar#getTime() 时,它指的是 下周,而不是当前周

请考虑以下代码 sn-p :

public class GetDatesOfWeek {

    public static void main(String[] args) {

        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

        Calendar cal = Calendar.getInstance();
        cal.set(1991, Calendar.DECEMBER, 11);

        //System.out.println(cal.getTime());//LINE NO : 14

        for(int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
            cal.set(Calendar.DAY_OF_WEEK, i);
            Date date = cal.getTime();
            System.out.println(sdf.format(date));
        }
    }

}

当我 取消注释 行号 14 我得到以下输出:

Wed Dec 11 07:38:06 IST 1991
08-12-1991
09-12-1991
10-12-1991
11-12-1991
12-12-1991
13-12-1991
14-12-1991

但是当我注释该行并执行代码时,我得到以下输出。

15-12-1991
16-12-1991
17-12-1991
18-12-1991
19-12-1991
20-12-1991
21-12-1991

请注意,在这两种情况下,月份和年份字段都是正确的,但开始日期从 08-12-1991 更改为 15-12-1991 对我来说 08-12-1991正确

我的问题:

  • 为什么在上述两种情况下我会得到不同的星期几?
  • 为什么 Java 会提供这种功能?

【问题讨论】:

  • 您是独立运行这两个测试,还是有代码在一次执行中一个接一个地运行它们?

标签: java date calendar


【解决方案1】:

如果您在调试器中单步执行您的代码,您会看到cal 对象的内部变量发生了有趣的事情。

日历对象分别存储它所代表的时间和调整字段。执行第 12 行后,使用当前时间构造 cal 对象,没有调整字段,并将其内部变量 isTimeSet 设置为 true。这意味着存储的内部时间是正确的。

执行第 13 行会将 isTimeSet 清除为 false,因为现在内部时间需要通过调整字段进行调整,然后才能再次准确。这不会立即发生,而是等待调用getTime()get(...)getTimeInMillis()add(...)roll(...)

第 14 行(如果未注释)强制使用调整字段重新计算内部时间,并将 isTimeSet 变量再次设置为 true。

然后第 17 行设置另一个调整字段,并再次取消设置 isTimeSet 变量。

第 18 行再次根据第 17 行中设置的调整字段重新计算正确的时间。

解决办法:

当您将设置日期与星期几结合使用时,会出现此问题。设置星期几时,忽略月份设置,以cal 对象中的当前月份为起点。因为今天是 12 日,1991 年 12 月 15 日是距离 1991 年 12 月 12 日最近的星期日,所以您恰好从 15 日开始一周。

注意:如果您在一周后再次运行测试,您将得到不同的结果。

解决方案是调用getTimeInMillis()getTime() 强制重新计算时间,然后再设置星期几调整。

测试:

如果您不想等待一周再进行测试,请尝试以下方法:

public class GetDatesOfWeek {

    public static void main(String[] args) {

        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

        Calendar cal = Calendar.getInstance();
        cal.set(2015, Calendar.AUGUST, 1); // adjust this date and see what happens
        cal.getTime();

        cal.set(1991, Calendar.DECEMBER, 11);
        //System.out.println(cal.getTime());//LINE NO : 14

        for(int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
            cal.set(Calendar.DAY_OF_WEEK, i);
            Date date = cal.getTime();
            System.out.println(sdf.format(date));
        }
    }

}

【讨论】:

  • 这也记录在 Java 文档中 可以通过调用 set 方法来设置日历字段值。在需要计算其时间值(距纪元的毫秒数)或日历字段的值之前,不会解释日历中设置的任何字段值。调用get、getTimeInMillis、getTime、add和roll都涉及到这样的计算。
猜你喜欢
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
相关资源
最近更新 更多