Java 日历的怪异行为

Java 日历的怪异行为,java,date,calendar,Java,Date,Calendar,我正面临着一种奇怪的行为 问题是当我在两者之间添加一个方法调用Calendar#getTime()时,我只能得到正确的结果,但是当我不调用Calendar#getTime()直接得到一周的日期时,它指的是下一周的而不是当前周的 请考虑以下代码片段: public class GetDatesOfWeek { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFor

我正面临着一种奇怪的行为

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

请考虑以下代码片段:

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));
        }
    }

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

15-12-1991
16-12-1991
17-12-1991
18-12-1991
19-12-1991
20-12-1991
21-12-1991
请注意,在这两种情况下,月份和年份字段都是正确的,但对于me而言,开始日期从
08-12-1991
更改为
15-12-1991
是正确的

我的问题:

  • 为什么在上述两种情况下我得到的是不同的一周日期
  • 为什么Java提供这种功能

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

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

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

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

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

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

解决方案:

当您将设置月份的哪一天与星期的哪一天结合起来时,就会出现此问题。设置星期几时,将忽略月日设置,并将
cal
对象中的当前月日用作起点。你正好从15号开始有一个星期,因为今天是12号,1991年12月15号是离1991年12月12号最近的星期日

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

解决方案是调用
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));
        }
    }

}
公共类GetDatesOfWeek{
公共静态void main(字符串[]args){
SimpleDataFormat sdf=新的SimpleDataFormat(“dd-MM-yyyy”);
Calendar cal=Calendar.getInstance();
cal.set(2015,Calendar.AUGUST,1);//调整此日期,看看会发生什么
cal.getTime();
cal.set(1991年,日历,12月11日);
//System.out.println(cal.getTime());//行号:14

对于(int i=Calendar.SUNDAY;i您是独立运行这两个测试,还是有代码在一次执行中一个接一个地运行它们?这也记录在Java文档中。可以通过调用set方法来设置日历字段值。日历中设置的任何字段值都不会被解释,直到需要计算其值为止时间值(从历元算起的毫秒)或日历字段的值。调用get、getTimeInMillis、getTime、add和roll都涉及此类计算。
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));
        }
    }

}