Java 日历 DAY_OF_WEEK 设置为零
Java Calendar DAY_OF_WEEK SET to zero
我有这个来自 PROD(> 7 年)的非常旧的代码块需要调试。有一点我无法理解。
代码中的一个部分会计算下一次任务将 运行 的时间,对于需要 运行 的任务,特别是在星期天、星期一,它使用 Calendar.SUNDAY。但是有一种说法即使在多次阅读文档后我也无法解释其行为
日历cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK, 0);
由于天数是从 1-7(Calendar.SUNDAY
到 Calendar.SATURDAY
)可以解释的,但是这里的零是如何工作的,为什么没有例外?
why there is no exception?
因为你没有设置宽松模式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
文档说:
Any out of range values are either normalized in lenient mode or
detected as an invalid value in non-lenient mode
作为规范化的一部分,值会翻转,例如以下代码将值设置为 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 被“溢出”时,“日历设置”看起来会调整 value/integer。
我可以看到这个模式:
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()
,因此实际上不可能传递超出 运行ge 的值。 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);
Exception in thread "main" java.time.DateTimeException: Invalid value
for DayOfWeek (valid values 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
教程link
Oracle tutorial: Date Time 解释如何使用 java.time.
我有这个来自 PROD(> 7 年)的非常旧的代码块需要调试。有一点我无法理解。 代码中的一个部分会计算下一次任务将 运行 的时间,对于需要 运行 的任务,特别是在星期天、星期一,它使用 Calendar.SUNDAY。但是有一种说法即使在多次阅读文档后我也无法解释其行为
日历cal = Calendar.getInstance(); cal.set(Calendar.DAY_OF_WEEK, 0);
由于天数是从 1-7(Calendar.SUNDAY
到 Calendar.SATURDAY
)可以解释的,但是这里的零是如何工作的,为什么没有例外?
why there is no exception?
因为你没有设置宽松模式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
文档说:
Any out of range values are either normalized in lenient mode or detected as an invalid value in non-lenient mode
作为规范化的一部分,值会翻转,例如以下代码将值设置为 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 被“溢出”时,“日历设置”看起来会调整 value/integer。 我可以看到这个模式:
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()
,因此实际上不可能传递超出 运行ge 的值。 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);
Exception in thread "main" java.time.DateTimeException: Invalid value for DayOfWeek (valid values 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
教程link
Oracle tutorial: Date Time 解释如何使用 java.time.