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

我想知道为什么'Y'返回2012年,而'y'在SimpleDateFormat返回2011年:

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

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

周年和年。 从javadoc

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

例如,1998年1月1日是星期四。 如果getFirstDayOfWeek()是MONDAY并且getMinimalDaysInFirstWeek()是4(ISO 8601标准兼容设置),那么1998年第一周从1997年12月29日开始,到1998年1月4日结束。周年是过去三天的1998年如果getFirstDayOfWeek()是SUNDAY,那么1998年第一周从1998年1月4日开始,到1998年1月10日结束。 1998年的前三天是1997年第53周的一部分,而一周是1997年。

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

新代码在WeekFields类中处理,特别是对于使用weekBasedYear()字段存取器的小写字母y /大写字母Y

根据此WeekField返回一个字段以访问基于星期的年份。 这代表了每周固定的星期开始的一年的概念,例如星期一和每周属于一年。 该字段通常与dayOfWeek()和weekOfWeekBasedYear()一起使用。

第一周(1)是从getFirstDayOfWeek()开始的一周,在该年至less有getMinimalDaysInFirstWeek()天。 因此,第一周可能会在年初之前开始。 如果第一周从今年年初开始,那么前一周是在上一年的最后一周。

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

在parsing的parsing阶段,可以从一个星期几,一年一个星期和一个星期几开始创build一个date。

在严格模式下,所有三个字段都会根据其有效值的范围进行validation。 每周的字段经过validation,以确保所得到的以周为基础的年份是按周要求的年份。

在智能模式下,所有三个字段都会根据其有效值的范围进行validation。 以周为基础的年份字段将从1到53进​​行validation,这意味着生成的date可以在下列以周为周期的年份中。

在宽松模式下,对照有效值的范围validation年份和星期几。 计算结果的date相当于以下三个阶段的方法。 首先,在所请求的每周基准年的第一周的第一天创build一个date。 然后采取星期几为基础的年份,减去一个,并添加数周的数量到date。 最后,在本地化的星期内调整到正确的星期几。

WeekFields实例的设置取决于语言环境,并可能根据不同的设置进行设置,像法国这样的美国和欧洲国家可能与本周开始的date不同。

例如,Java 8的DateFormatterBuilder ,使用语言环境实例化parsing器,并将该语言环境用于Y符号:

 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))); 

如果日历支持周年,则格式化Y得到周年。 ( getCalendar().isWeekDateSupported()

我学会了JSTL标签库format:date的难题format:date short因为请求的格式使用YYYY。 这确实可以在一年之前推出印刷date。