Y devuelve 2012 mientras que y devuelve 2011 en SimpleDateFormat

7 minutos de lectura

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é?

  • Solo como una nota para futuros lectores: este comportamiento solo ocurrirá durante la última semana del año o la primera semana del año.

    – ventaja

    5 de enero de 2014 a las 19:05

semana año y año De javadoc

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

Por ejemplo, el 1 de enero de 1998 es jueves. Si getFirstDayOfWeek() es LUNES y getMinimalDaysInFirstWeek() es 4 (configuración compatible con el estándar ISO 8601), entonces 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 año de semana es 1997.

  • $ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 Algunos programas se confunden: strftime calcula hoy (29/12/2015) como si tuviera la semana 53, y semana-año como 2015.

    – Aks

    30 de diciembre de 2015 a las 0:43


Y devuelve 2012 mientras que y devuelve 2011 en SimpleDateFormat
Brice

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 el WeekFields clase, y específicamente para la minúscula y / mayúscula Y con el weekBasedYear() accesor 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 getMinimalDaysInFirstWeek() días 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 contra 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 basado en la semana solicitado.

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

En el 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 en el primer día de la primera semana en el año solicitado basado en la semana. Luego tome el año basado en la semana de la semana, reste uno y agregue la cantidad en semanas a la fecha. Finalmente, ajuste al día de la semana correcto dentro de la semana localizada.

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

por ejemplo el DateFormatterBuilder de Java 8, cree una instancia del analizador con la configuración regional y use esta configuración regional para el Y sí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 con respecto a la configuración regional y la mayúscula Ypuedes jugar con la opción de línea de comando -Duser.language= (fr, en, esetc.), o fuerce 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)));

Y devuelve 2012 mientras que y devuelve 2011 en SimpleDateFormat
KV Prajápati

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

Aprendí por las malas la biblioteca de etiquetas JSTL format:date con short ya que el formato solicitado usa YYYY debajo de las portadas. Lo que de hecho puede adelantar la fecha impresa un año.

Y devuelve 2012 mientras que y devuelve 2011 en SimpleDateFormat
JGFMK

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

¡Observa cómo avanza uno!

Esto es malo: ¡YYYY!
AAAA

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: yyyy

aaaa

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad