Y devuelve 2012 mientras y vuelve 2011 en SimpleDateFormat

Me pregunto por qué ‘Y’ devuelve 2012, mientras que ‘y’ devuelve 2011 en SimpleDateFormat :

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

¿Alguien puede explicar por qué?

semana año y año. De javadoc

Un año de la semana está sincronizado con un ciclo WEEK_OF_YEAR. Todas las semanas entre la primera y la última semana (inclusive) tienen el mismo valor de año de la semana. Por lo tanto, el primer y último día de un año de una semana pueden tener diferentes valores de año calendario.

Por ejemplo, el 1 de enero de 1998 es un jueves. Si getFirstDayOfWeek () es MONDAY y getMinimalDaysInFirstWeek () es 4 (ajuste compatible con ISO 8601), la semana 1 de 1998 comienza el 29 de diciembre de 1997 y finaliza el 4 de enero de 1998. El año de la semana es 1998 durante los últimos tres días del año calendario 1997. Sin embargo, si getFirstDayOfWeek () es DOMINGO, entonces la semana 1 de 1998 comienza el 4 de enero de 1998 y finaliza el 10 de enero de 1998; los primeros tres días de 1998 son parte de la semana 53 de 1997 y su semana es 1997.

Aquí hay una actualización de Java 8 con algún código, ya que GregorianCalendar probablemente se desaprovechará o eliminará de futuras versiones de JDK.

El nuevo código se maneja en la clase WeekFields , y específicamente para la minúscula y / mayúscula Y con el weekBasedYear() campo weekBasedYear() .

Devuelve un campo para acceder al año de una semana basada en este WeekFields. Esto representa el concepto del año en el que las semanas comienzan en un día fijo de la semana, como el lunes y cada semana pertenece exactamente a un año. Este campo se usa generalmente con dayOfWeek () y weekOfWeekBasedYear ().

La semana uno (1) es la semana que comienza en getFirstDayOfWeek () donde hay al menos días getMinimalDaysInFirstWeek () en el año. Por lo tanto, la primera semana puede comenzar antes del comienzo del año. Si la primera semana comienza después del comienzo del año, entonces el período anterior es la última semana del año anterior.

Este campo se puede usar con cualquier sistema de calendario.

En la fase de resolución del análisis sintáctico, se puede crear una fecha a partir de un año basado en una semana, una semana del año y un día de la semana.

En modo estricto, los tres campos se validan contra su rango de valores válidos. El campo de la semana del año se valida para garantizar que el año de la semana resultante sea el año de la semana solicitada.

En modo inteligente, los tres campos se validan contra su rango de valores válidos. El campo del año de la semana de la semana se valida de 1 a 53, lo que significa que la fecha resultante puede estar en el siguiente año basado en la semana según lo especificado.

En modo indulgente, el año y el día de la semana se validan contra el rango de valores válidos. La fecha resultante se calcula equivalente al siguiente enfoque de tres etapas. Primero, cree una fecha el primer día de la primera semana en el año de la semana solicitada. Luego tome el año de la semana de la semana, reste uno y agregue el monto en semanas a la fecha. Finalmente, ajuste al día de la semana correcto dentro de la semana localizada.

La configuración de esta instancia de WeekFields depende de la configuración regional y puede tener diferentes configuraciones, los países de EE. UU. Y Europa, como Francia, pueden tener un día diferente al comienzo de la semana.

Por ejemplo, DateFormatterBuilder de Java 8, DateFormatterBuilder una instancia del analizador con la configuración regional y usa esta configuración regional para el símbolo 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); } ... } ... } 

Aquí hay un ejemplo

 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 en cuanto a la configuración regional y la mayúscula Y , puede jugar con la opción de línea de comando -Duser.language= ( fr , en , es , etc.), o forzar la configuración regional en el momento de la invocación:

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

Formatee Y para obtener el año de la semana si el calendario admite la semana del año. ( getCalendar().isWeekDateSupported() )

Aprendí de la manera más difícil el format:date biblioteca de tags JSTL format:date con un short ya que el formato solicitado usa YYYY debajo de las carátulas. Que de hecho puede rodar la fecha impresa por delante un año.