Java日历日设置为零

Java日历日设置为零,java,calendar,dayofweek,Java,Calendar,Dayofweek,我有一个来自PROD(>7年)的非常旧的代码块需要调试。有一点我不明白。 代码中的一个部分计算任务下次运行的时间,对于需要在星期天运行的任务,它使用Calendar.sunday。但有一种说法,即使在多次阅读文档后,我也无法解释其行为 Calendar cal=Calendar.getInstance(); 校准设置(日历日/周,0) 由于天数是从1-7(Calendar.SUNDAY到Calendar.SATURDAY)来计算的,因此可以解释,但是零在这里是如何工作的,为什么没有例外 为什么没

我有一个来自PROD(>7年)的非常旧的代码块需要调试。有一点我不明白。 代码中的一个部分计算任务下次运行的时间,对于需要在星期天运行的任务,它使用Calendar.sunday。但有一种说法,即使在多次阅读文档后,我也无法解释其行为

Calendar cal=Calendar.getInstance(); 校准设置(日历日/周,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
输出:

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-设置值时没有执行任何验证。只有在检索值时,如果在非宽容模式下检测到无效值,才会出现异常。