问题描述
我有这个来自 PROD(> 7 年)的非常旧的代码块需要调试。有一点我不明白。 代码中的一个部分计算下一次任务将运行的时间,对于需要专门在星期日、星期一运行的任务,它使用 Calendar.SUNDAY。但是有一个语句的行为即使在多次阅读文档后我也无法解释
日历校准 = Calendar.getInstance(); cal.set(Calendar.DAY_OF_WEEK,0);
既然天数是从 1-7(Calendar.SUNDAY
到 Calendar.SATURDAY
)可以解释的,但是零在这里是如何工作的,为什么没有例外?
解决方法
为什么没有例外?
这是因为您没有将宽松模式设置为false
,默认为true
。
演示:
import java.util.Calendar;
public class Main {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.set(Calendar.DAY_OF_WEEK,0);
System.out.println(cal.getTime());
}
}
输出:
Exception in thread "main" java.lang.IllegalArgumentException: DAY_OF_WEEK
文档说:
任何超出范围的值要么在宽松模式下标准化,要么 在非宽松模式下检测为无效值
作为归一化的一部分,该值被翻转,例如以下代码将值设置为等效于 cal.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY - 1)
:
cal.set(Calendar.DAY_OF_WEEK,0);
类似地,下面的代码设置等效于 cal.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY - 2)
的值:
cal.set(Calendar.DAY_OF_WEEK,-1);
,
通过在“测试台”中进行尝试,我发现了这一点:
当数字 1-7“溢出”时,它看起来是“日历集”调整值/整数。 我可以看到这种模式:
Day Of Week: 1 2 3 4 5 6 7 | 1 2 3 4 5 6 7 | 1 2 3 4 5 6 7 | ...
Value of calendar: -6 -5 -4 -3 -2 -1 0 | 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 | ...
测试台:
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK,-6);
System.out.println("Calendar value -6 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK,0);
System.out.println("Calendar value 0 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK,1);
System.out.println("Calendar value 1 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK,7);
System.out.println("Calendar value 7 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK,8);
System.out.println("Calendar value 8 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK,14);
System.out.println("Calendar value 14 returns: " + cal.get(Calendar.DAY_OF_WEEK));
}
输出:
Calendar value -6 returns: 1
Calendar value 0 returns: 7
Calendar value 1 returns: 1
Calendar value 7 returns: 7
Calendar value 8 returns: 1
Calendar value 14 returns: 7
输出是根据“模式”。
,java.time
我建议您使用 java.time,现代 Java 日期和时间 API,用于您的日期和时间工作。例如:
LocalDate ld = LocalDate.now(ZoneId.systemDefault())
.with(DayOfWeek.TUESDAY);
System.out.println(ld);
今天(6 月 5 日星期六)运行此代码时,输出为:
2021-06-01
是的,6 月 1 日是星期二。由于我们将枚举常量传递给 with()
,因此实际上不可能传递超出范围的值。 DayOfWeek
是一个枚举,包含一周 7 天的 7 个值。我们唯一会遇到的麻烦是传递 null
,这将抛出一个 NullPointerException
,我认为这是您想要的。
如果我们确实坚持将星期几作为数字传递,那是可能的。 java.time 将一周中的天数从星期一 = 1 到星期日 = 7。
LocalDate ld = LocalDate.now(ZoneId.systemDefault())
.with(ChronoField.DAY_OF_WEEK,2);
到目前为止,输出和以前一样是 2021-06-01
。但是如果我们传递 0 呢?
.with(ChronoField.DAY_OF_WEEK,0);
线程“main”中的异常 java.time.DateTimeException: Invalid value 对于 DayOfWeek(有效值 1 - 7):0
我们不仅收到了您要求的例外情况,而且还收到了清晰且有用的例外消息,恕我直言。
星期零在这里是如何工作的?
使用 Calendar
周中的第 0 天与 7 = 星期六相同。似乎至少有一个宽松的老式 GregorianCalendar
在一周中的某一天执行一种模 7 运算以将其置于区间 1 到 7 内。我没有发现这个记录。 GregorianCalendar
可能是您正在处理的 Calendar
的具体子类。我尝试了不同的数字,它们都等价于 7 模 7:
int[] dows = { 0,7,-7,14,-14,-98 };
for (int dow : dows) {
Calendar cal = new GregorianCalendar(2021,Calendar.JUNE,2);
Date dateBefore = cal.getTime();
cal.set(Calendar.DAY_OF_WEEK,dow);
System.out.format("%s and day of week %3d yields %s%n",dateBefore,dow,cal.getTime());
}
输出:
Wed Jun 02 00:00:00 CEST 2021 and day of week 0 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week 7 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week -7 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week 14 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week -14 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week -98 yields Sat Jun 05 00:00:00 CEST 2021
教程链接
Oracle tutorial: Date Time 解释如何使用 java.time。