Y 返回 2012,而 y 在 SimpleDateFormat 中返回 2011

2022-08-31 11:04:50

我想知道为什么“Y”返回2012,而“y”返回2011:SimpleDateFormat

System.out.println(new SimpleDateFormat("Y").format(new Date())); // prints 2012
System.out.println(new SimpleDateFormat("y").format(new Date())); // prints 2011

任何人都可以解释为什么吗?


答案 1

周年和年。来自 javadoc

一周与WEEK_OF_YEAR周期同步。第一周和最后一周(含)之间的所有周都具有相同的周年值。因此,一周年的第一天和最后几天可能具有不同的日历年值。

例如,1998 年 1 月 1 日是星期四。如果 getFirstDayOfWeek() 是 Monday,getMinimalDaysInFirstWeek() 是 4(ISO 8601 标准兼容设置),则 1998 年第 1 周从 1997 年 12 月 29 日开始,到 1998 年 1 月 4 日结束。1997日历年最后三天的周年是1998年。但是,如果 getFirstDayOfWeek() 是 SUNDAY,则 1998 年的第 1 周从 1998 年 1 月 4 日开始,到 1998 年 1 月 10 日结束;1998年的前三天是1997年第53周的一部分,他们的周年是1997年。


答案 2

这是一个包含一些代码的Java 8更新,因为GregorianCalendar可能会被弃用或从未来的JDK版本中删除。

新代码在类中处理,并且专门用于小写/大写与weetBasedYear()字段访问器。WeekFieldsyY

返回一个字段,用于访问基于周的年份的年份基于此周字段。这表示一年的概念,其中周在固定的星期几(如星期一)开始,并且每周正好属于一年。此字段通常与 dayOfWeek() 和 weekOfWeekBasedYear() 一起使用。

第一周(1)是从getFirstDayOfWeek()开始的一周,其中一年中至少有getMinimalDaysInFirstWeek()天。因此,第一周可以在年初之前开始。如果第一周在年初之后开始,则之前的时间段是在前一年的最后一周。

此字段可用于任何日历系统。

在解析的解析阶段,可以从基于周的年、年中的周和星期几创建日期。

在严格模式下,所有三个字段都根据其有效值范围进行验证。对“一年中的周”字段进行验证,以确保生成的基于周的年份是请求的基于周的年份。

在智能模式下,所有三个字段都根据其有效值范围进行验证。基于周的年份字段从 1 到 53 进行验证,这意味着生成的日期可以是指定的下一个基于周的年份。

在宽松模式下,将根据有效值的范围验证年份和星期几。结果日期的计算等效于以下三个阶段的方法。首先,在请求的基于周的年份中第一周的第一天创建一个日期。然后取基于周的年份,减去一个,并将以周为单位的金额添加到日期中。最后,在本地化的一周内调整到正确的星期几。

此实例的设置取决于区域设置,并且可能具有不同的设置,具体取决于它,美国和欧洲国家/地区(如法国)可能具有不同的一天作为一周的开始时间。WeekFields

例如 Java 8,使用语言环境实例化解析器,并将以下语言环境用于符号:DateFormatterBuilderY

public final class DateTimeFormatterBuilder {
    ...

    private void parsePattern(String pattern) {
        ...
                } else if (cur == 'Y') {
                    // Fields defined by Locale
                    appendInternal(new WeekBasedFieldPrinterParser(cur, count));
                } else {
        ...


    static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {
        ...

        /**
         * Gets the printerParser to use based on the field and the locale.
         *
         * @param locale  the locale to use, not null
         * @return the formatter, not null
         * @throws IllegalArgumentException if the formatter cannot be found
         */
        private DateTimePrinterParser printerParser(Locale locale) {
            WeekFields weekDef = WeekFields.of(locale);
            TemporalField field = null;
            switch (chr) {
                case 'Y':
                    field = weekDef.weekBasedYear();
                    if (count == 2) {
                        return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0);
                    } else {
                        return new NumberPrinterParser(field, count, 19,
                                                       (count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1);
                    }
                case 'e':
                case 'c':
                    field = weekDef.dayOfWeek();
                    break;
                case 'w':
                    field = weekDef.weekOfWeekBasedYear();
                    break;
                case 'W':
                    field = weekDef.weekOfMonth();
                    break;
                default:
                    throw new IllegalStateException("unreachable");
            }
            return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE);
        }

        ...
    }

    ...
}

下面是一些示例

System.out.format("Conundrum                         : %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
                               .format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'")));
System.out.format("Solution                          : %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
                               .format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmms'S'")));


System.out.format("JVM Locale first day of week      : %s%n",
                  WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
System.out.format("US first day of week              : %s%n",
                  WeekFields.of(Locale.US).getFirstDayOfWeek());
System.out.format("France first day of week          : %s%n",
                  WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());
System.out.format("JVM Locale min days in 1st week   : %s%n",
                  WeekFields.of(Locale.getDefault()).getMinimalDaysInFirstWeek());
System.out.format("US min days in 1st week           : %s%n",
                  WeekFields.of(Locale.US).getMinimalDaysInFirstWeek());
System.out.format("JVM Locale min days in 1st week   : %s%n",
                  WeekFields.of(Locale.FRANCE).getMinimalDaysInFirstWeek());

System.out.format("JVM Locale week based year (big Y): %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear()));
System.out.format("France week based year (big Y)    : %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear()));
System.out.format("US week based year (big Y)        : %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.US).weekBasedYear()));

关于区域设置和大写字母,您可以使用命令行选项(,,等),或者在调用时强制使用区域设置:Y-Duser.language=frenes

System.out.format("English localized                 : %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
                               .format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.ENGLISH)));
System.out.format("French localized                  : %s%n",
                  ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
                               .format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.FRENCH)));