Y retorna 2012 enquanto y retorna 2011 em SimpleDateFormat


85

Eu me pergunto por que 'Y' retorna 2012 enquanto 'y' retorna 2011 em SimpleDateFormat:

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

Alguém pode explicar por quê?


36
Apenas uma observação para os futuros leitores: esse comportamento só acontecerá na última semana do ano ou na primeira semana do ano.
ryvantage

Respostas:


91

semana ano e ano. De Javadoc

Um ano semanal está sincronizado com um ciclo WEEK_OF_YEAR. Todas as semanas entre a primeira e a última semana (inclusive) têm o mesmo valor de ano da semana. Portanto, o primeiro e o último dias de um ano de semana podem ter valores de ano civil diferentes.

Por exemplo, 1º de janeiro de 1998 é uma quinta-feira. Se getFirstDayOfWeek () for MONDAY e getMinimalDaysInFirstWeek () for 4 (configuração compatível com o padrão ISO 8601), a semana 1 de 1998 começa em 29 de dezembro de 1997 e termina em 4 de janeiro de 1998. O ano da semana é 1998 para os últimos três dias do ano civil de 1997. Se, entretanto, getFirstDayOfWeek () for SUNDAY, a semana 1 de 1998 começará em 4 de janeiro de 1998 e terminará em 10 de janeiro de 1998; os primeiros três dias de 1998 fazem parte da semana 53 de 1997 e o ano da semana é 1997.


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 Alguns software está confuso: strftimecalcula hoje (2015/12/29) como tendo semana 53 e semana-ano como 2015.
aks

11

Aqui está uma atualização do Java 8 com algum código, já que GregorianCalendar provavelmente será descontinuado ou removido de versões futuras do JDK.

O novo código é tratado na WeekFieldsclasse e especificamente para maiúsculas y/ minúsculas Ycom o weekBasedYear()acessador de campo.

Retorna um campo para acessar o ano de um ano baseado na semana com base neste WeekFields. Isso representa o conceito do ano em que as semanas começam em um dia fixo da semana, como segunda-feira e cada semana pertence a exatamente um ano. Este campo é normalmente usado com dayOfWeek () e weekOfWeekBasedYear ().

A semana um (1) é a semana que começa em getFirstDayOfWeek (), onde há pelo menos getMinimalDaysInFirstWeek () dias no ano. Assim, a primeira semana pode começar antes do início do ano. Se a primeira semana começar após o início do ano, o período anterior será na última semana do ano anterior.

Este campo pode ser usado com qualquer sistema de calendário.

Na fase de resolução da análise, uma data pode ser criada a partir de um ano com base na semana, semana do ano e dia da semana.

No modo estrito, todos os três campos são validados em relação a sua faixa de valores válidos. O campo semana do ano é validado para garantir que o ano baseado na semana resultante seja o ano baseado na semana solicitado.

No modo inteligente, todos os três campos são validados em relação a sua faixa de valores válidos. O campo do ano com base na semana é validado de 1 a 53, o que significa que a data resultante pode estar no ano com base na semana seguinte ao especificado.

No modo tolerante, o ano e o dia da semana são validados em relação ao intervalo de valores válidos. A data resultante é calculada de forma equivalente à seguinte abordagem de três estágios. Primeiro, crie uma data no primeiro dia da primeira semana no ano com base na semana solicitado. Em seguida, pegue o ano baseado na semana da semana, subtraia um e adicione a quantidade em semanas à data. Finalmente, ajuste o dia da semana correto dentro da semana localizada.

A configuração desta WeekFieldsinstância depende da localidade e pode ter configurações diferentes dependendo dela, os EUA e países europeus como a França podem ter um dia diferente como início da semana.

Por exemplo, o DateFormatterBuilderdo Java 8, instancie o analisador com a localidade e use esta localidade para o 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);
        }

        ...
    }

    ...
}

Aqui está um exemplo

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

E no que diz respeito do local e maiúsculas Y, você pode jogar com a opção de linha de comando -Duser.language=( fr, en, es, etc.), ou forçar o local em tempo de invocação:

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

5

Formato Ypara obter o ano da semana se o calendário suportar o ano da semana. ( getCalendar().isWeekDateSupported())


1

Aprendi da maneira mais difícil que a biblioteca de tags JSTL format:datecom shorto formato solicitado usa YYYY nos bastidores. O que pode realmente adiantar a data impressa um ano.


0

Eu converto uma data para frente e para trás - você esperaria o mesmo ano ao fazer isso.

Observe como avança um!

Isso é ruim: YYYY! AAAA

Você pode executá-lo aqui .

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

Isso é bom: aaaa

aaaa

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.