Y devuelve 2012 mientras que y devuelve 2011 en SimpleDateFormat

85

Me pregunto por qué 'Y' regresa 2012 mientras que 'y' regresa 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é?

Ing.Fouad
fuente
36
Solo como una nota para los futuros lectores: este comportamiento solo ocurrirá durante la última semana del año o la primera semana del año.
Ryvantage

Respuestas:

91

semana año y año. De javadoc

Un año semanal 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 semana. Por lo tanto, el primer y último día de un año de la semana pueden tener diferentes valores de año calendario.

Por ejemplo, el 1 de enero de 1998 es jueves. Si getFirstDayOfWeek () es MONDAY y getMinimalDaysInFirstWeek () es 4 (configuración compatible con el estándar 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 forman parte de la semana 53 de 1997 y su año semanal es 1997.

Aravind Yarram
fuente
$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 Algún software se confunde: strftimecalcula hoy (29/12/2015) como si tuviera la semana 53 y la semana-año como 2015.
aks
11

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

El nuevo código se maneja en la WeekFieldsclase, y específicamente para minúsculas y/ mayúsculas Ycon el descriptor de weekBasedYear()acceso de campo.

Devuelve un campo para acceder al año de un año basado en semanas basado 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 normalmente 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 semana uno puede comenzar antes del comienzo del año. Si la primera semana comienza después del comienzo del año, el período anterior corresponde a la última semana del año anterior.

Este campo se puede utilizar con cualquier sistema de calendario.

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

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

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

En modo indulgente, el año y el día de la semana se validan con 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 del año basado en la semana solicitado. Luego, tome el año basado en la semana de la semana, reste uno y agregue la cantidad en semanas a la fecha. Finalmente, ajústese al día de la semana correcto dentro de la semana localizada.

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

Por ejemplo, DateFormatterBuilderde Java 8, cree una instancia del analizador con la configuración regional y use esta configuración regional para el Ysímbolo:

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 lo que se refiere a la configuración regional y la carcasa superior Y, se puede jugar ya sea con la opción de línea de comandos -Duser.language=( fr, en, es, etc.), o forzar la configuración regional en tiempo de 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)));
Brice
fuente
5

Formato Ypara obtener el año de la semana si el calendario admite el año de la semana. ( getCalendar().isWeekDateSupported())

adatapost
fuente
1

He aprendido de la manera difícil la biblioteca de etiquetas JSTL format:datecon shortque el formato solicitado utiliza AAAA bajo las sábanas. Lo que de hecho puede adelantar la fecha impresa un año.

Erica Kane
fuente
0

Convierto una fecha de un lado a otro: esperaría el mismo año cuando haga esto.

¡Fíjate cómo avanza uno!

Esto es malo: ¡YYYY! YYYY

Puedes ejecutarlo aquí .

import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static java.lang.System.out;
class Playground {
    public static Date convertYYYYMMDDStr(String s) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date result = null;
        try {
            result = sdf.parse(s);
        } catch(ParseException e) {
            e.printStackTrace();
        }
        return result;
    }
    public static String formatDateToStrWithSDF(Date d, SimpleDateFormat s) {
        return s.format(d);
    }
    public static void main(String[ ] args) {
        // DON'T DO. Use yyyy instead of YYYY
        SimpleDateFormat sdfdmy = new SimpleDateFormat("dd-MM-YYYY"); 
        String jan1st2020sb = "2020-01-01";
        Date jan1st2020d = convertYYYYMMDDStr(jan1st2020sb);
        String jan1st2020sa = formatDateToStrWithSDF(jan1st2020d, sdfdmy);
        out.println(jan1st2020sb);
        out.println(jan1st2020d);
        out.println(jan1st2020sa);
        String dec31st2020sb = "2020-12-31";
        Date dec31st2020d = convertYYYYMMDDStr(dec31st2020sb);
        String dec31st2020sa = formatDateToStrWithSDF(dec31st2020d, sdfdmy);
        out.println(dec31st2020sb);
        out.println(dec31st2020d);
        out.println(dec31st2020sa);
    }
}

Esto es bueno: aaaa

aaaa

JGFMK
fuente