无法创建表示 2019 年 12 月 29 日的日期对象

Cannot create a Date object representing December 29, 2019

我希望这不是 JDK 错误,否则我很想兑现我所有的银行账户并把它扔进床垫... 这是代码。请注意,将日期设置为 12 月 29 日会立即将年份滚动到 2020 年。此外,toString() 输出显示 Calendar 似乎认为周数是“1”。

import java.util.*; // headers MUST be above the first class
import java.text.*;

public class JDKCalendarBug {

    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-YYYY kk:mm");
        Calendar cal = java.util.Calendar.getInstance(TimeZone
                .getTimeZone("EST"));
        cal.clear();
        cal.set(Calendar.YEAR, 2019);
        cal.set(Calendar.MONTH, Calendar.DECEMBER);

        cal.set(Calendar.DAY_OF_MONTH, 26);
        Date t = cal.getTime();
        System.out.print("\n"+sdf.format(t));
        System.out.print("\n"+cal.toString());

        cal.set(Calendar.DAY_OF_MONTH, 27);
        t = cal.getTime();
        System.out.print("\n"+sdf.format(t));
        System.out.print("\n"+cal.toString());

        cal.set(Calendar.DAY_OF_MONTH, 28);
        t = cal.getTime();
        System.out.print("\n"+sdf.format(t));
        System.out.print("\n"+cal.toString());

        cal.set(Calendar.DAY_OF_MONTH, 29);
        t = cal.getTime();
        System.out.print("\n"+sdf.format(t));
        System.out.print("\n"+cal.toString());

    }

}

输出:

12-26-2019 24:00 java.util.GregorianCalendar[time=1577336400000,areFieldsSet=true,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="EST",offset=-18000000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2019,MONTH=11,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=26,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=?,HOUR=?,HOUR_OF_DAY=?,MINUTE=?,SECOND=?,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]

12-27-2019 24:00 java.util.GregorianCalendar[time=1577422800000,areFieldsSet=true,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="EST",offset=-18000000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=11,WEEK_OF_YEAR=52,WEEK_OF_MONTH=4,DAY_OF_MONTH=27,DAY_OF_YEAR=361,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=4,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-18000000,DST_OFFSET=0] 12-28-2019 24:00 java.util.GregorianCalendar[time=1577509200000,areFieldsSet=true,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="EST",offset=-18000000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=11,WEEK_OF_YEAR=52,WEEK_OF_MONTH=4,DAY_OF_MONTH=28,DAY_OF_YEAR=362,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=4,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-18000000,DST_OFFSET=0]

12-29-2020 24:00 java.util.GregorianCalendar[time=1577595600000,areFieldsSet=true,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="EST",offset=-18000000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=11,WEEK_OF_YEAR=1,WEEK_OF_MONTH=5,DAY_OF_MONTH=29,DAY_OF_YEAR=363,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=5,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-18000000,DST_OFFSET=0]

问题出在 SimpleDateFormat。如果您将格式字符串更改为小写 ys,则日期格式正确为 12-29-2019 24:00

new SimpleDateFormat("MM-dd-yyyy kk:mm")

Y 对应于 "Week Year",它与 "Year" 不同,并非所有日历都支持。根据 JavaDocs:

If week year 'Y' is specified and the calendar doesn't support any week years, the calendar year ('y') is used instead. The support of week years can be tested with a call to getCalendar().isWeekDateSupported().

在这种情况下,支持 "week year",因为底层 Calendar 实现是 GregorianCalendar。根据其 JavaDocs:

A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between the first and last weeks (inclusive) have the same week year value. Therefore, the first and last days of a week year may have different calendar year values.