日历的奇怪行为
Weird behavior of Calendar
我遇到了 java.util.Calendar
的奇怪行为。
问题是,当我在两者之间添加一个方法调用 Calendar#getTime()
时,我得到了正确的结果,但是当我直接获得一周的 Dates
而没有调用 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));
}
}
}
当我取消注释第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 中提供了这种功能?
如果您在调试器中单步执行代码,您会发现 cal
对象的内部变量发生了一些有趣的事情。
日历对象分别存储它表示的时间和调整字段。执行第 12 行后,构造了包含当前时间且没有调整字段的 cal 对象,并将其内部变量 isTimeSet
设置为 true。这意味着存储的内部时间是正确的。
执行第 13 行会将 isTimeSet
清除为假,因为现在内部时间需要通过调整字段进行调整才能再次准确。这不会立即发生,而是等待调用 getTime()
或 get(...)
、getTimeInMillis()
、add(...)
或 roll(...)
.
第 14 行(如果未注释)强制使用调整字段重新计算内部时间,并再次将 isTimeSet
变量设置为 true。
第 17 行然后设置另一个调整字段,并再次取消设置 isTimeSet
变量。
第 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));
}
}
}
我遇到了 java.util.Calendar
的奇怪行为。
问题是,当我在两者之间添加一个方法调用 Calendar#getTime()
时,我得到了正确的结果,但是当我直接获得一周的 Dates
而没有调用 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));
}
}
}
当我取消注释第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 中提供了这种功能?
如果您在调试器中单步执行代码,您会发现 cal
对象的内部变量发生了一些有趣的事情。
日历对象分别存储它表示的时间和调整字段。执行第 12 行后,构造了包含当前时间且没有调整字段的 cal 对象,并将其内部变量 isTimeSet
设置为 true。这意味着存储的内部时间是正确的。
执行第 13 行会将 isTimeSet
清除为假,因为现在内部时间需要通过调整字段进行调整才能再次准确。这不会立即发生,而是等待调用 getTime()
或 get(...)
、getTimeInMillis()
、add(...)
或 roll(...)
.
第 14 行(如果未注释)强制使用调整字段重新计算内部时间,并再次将 isTimeSet
变量设置为 true。
第 17 行然后设置另一个调整字段,并再次取消设置 isTimeSet
变量。
第 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));
}
}
}