Java日历日设置为零
我有一个来自PROD(>7年)的非常旧的代码块需要调试。有一点我不明白。 代码中的一个部分计算任务下次运行的时间,对于需要在星期天运行的任务,它使用Calendar.sunday。但有一种说法,即使在多次阅读文档后,我也无法解释其行为 Calendar cal=Calendar.getInstance(); 校准设置(日历日/周,0) 由于天数是从1-7(Java日历日设置为零,java,calendar,dayofweek,Java,Calendar,Dayofweek,我有一个来自PROD(>7年)的非常旧的代码块需要调试。有一点我不明白。 代码中的一个部分计算任务下次运行的时间,对于需要在星期天运行的任务,它使用Calendar.sunday。但有一种说法,即使在多次阅读文档后,我也无法解释其行为 Calendar cal=Calendar.getInstance(); 校准设置(日历日/周,0) 由于天数是从1-7(Calendar.SUNDAY到Calendar.SATURDAY)来计算的,因此可以解释,但是零在这里是如何工作的,为什么没有例外 为什么没
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
输出:
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\u of_WEEK,Calendar.SUNDAY-1)
:
类似地,以下代码设置的值相当于cal.set(Calendar.DAY\u OF_WEEK,Calendar.SUNDAY-2)
:
通过在“试验台”上进行试验,我发现:
当数字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
是的,六月一日是星期二。由于我们正在使用()将枚举常量传递给,
,因此实际上不可能传递超出范围的值DayOfWeek
是一个枚举,在一周的7天中包含7个值。我们唯一能遇到的麻烦是通过传递null
,这将抛出一个NullPointerException
,我想这是您想要的
但是,如果我们坚持把一周中的某一天作为一个数字,那是可能的。java.time表示一周中从周一到周日的天数
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中的异常:无效值
对于DayOfWeek(有效值1-7):0
我们不仅得到了您要求的异常,我们还得到了一条清晰而有用的异常消息,IMHO
零号工作日在这里是怎么工作的?
使用日历
一周中的第0天与第7天=星期六的工作方式相同。似乎至少有一种宽大的老式的gregoriacalendar
在一周中的某一天执行一种模7运算,将其置于1到7的区间内。我没有发现这个文件gregoriacalendar
可能是您正在处理的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());
}
输出:
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包中的替换项编写代码,同时通过从添加到旧类的方法调用new
到
/来轻松地来回转换代码。我建议您不要使用日历
。那门课设计得很糟糕,而且早已过时。而是使用来自的类,例如LocalDate
或ZonedDateTime
。了解这一点很有意思。奇怪的是,在调用getTime()之前,即使将Lenient mode设置为false,也可以毫无例外地设置值0。@dora-设置值时没有执行任何验证。只有在检索值时,如果在非宽容模式下检测到无效值,才会出现异常。