Y возвращает 2012, а Y возвращает 2011 в SimpleDateFormat - PullRequest
72 голосов
/ 31 декабря 2011

Интересно, почему «Y» возвращает 2012, а «y» возвращает 2011 в SimpleDateFormat:

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

Может кто-нибудь объяснить, почему?

Ответы [ 4 ]

76 голосов
/ 31 декабря 2011

год недели и год. От Javadoc

Недельный год синхронизирован с циклом WEEK_OF_YEAR. Все недели между первая и последняя недели (включительно) имеют одинаковое значение года недели. Следовательно, первый и последний дни недели года могут иметь разные значения календарного года.

Например, 1 января 1998 года - четверг. Если getFirstDayOfWeek () Понедельник и getMinimalDaysInFirstWeek () равны 4 (стандарт ISO 8601 совместимая настройка), затем первая неделя 1998 г. начинается 29 декабря 1997 г., и заканчивается 4 января 1998 года. Недельный год 1998 для последних трех дни календарного 1997 года. Если, однако, getFirstDayOfWeek () Воскресенье, затем первая неделя 1998 года начинается 4 января 1998 года и заканчивается 10 января 1998 г .; первые три дня 1998 года являются частью недели 53 из 1997 года и их недельный год - 1997.

11 голосов
/ 04 января 2016

Вот обновление Java 8 с некоторым кодом, поскольку GregorianCalendar, вероятно, будет исключен или удален из будущих версий JDK.

Новый код обрабатывается в классе WeekFields, и особенно в нижнем регистре y / верхний регистр Y с полем доступа weekBasedYear().

Возвращает поле для доступа к году недельного года на основе этого WeekFields.Это представляет концепцию года, когда недели начинаются с фиксированного дня недели, такого как понедельник, и каждая неделя принадлежит ровно одному году.Это поле обычно используется с dayOfWeek () и weekOfWeekBasedYear ().

Week one (1) - это неделя, начинающаяся с getFirstDayOfWeek (), где в году есть как минимум getMinimalDaysInFirstWeek () дней. Таким образом, первая неделя может начаться до начала года.Если первая неделя начинается после начала года, то предыдущий период относится к последней неделе предыдущего года.

Это поле можно использовать с любой календарной системой.

На этапе разрешения синтаксического анализа можно создать дату из года в неделю, недели в году и дня недели.

В строгом режиме все три поля проверяются по их диапазонудействительных значений.Поле недели года проверяется, чтобы убедиться, что итоговый недельный год является запрошенным недельным годом.

В интеллектуальном режиме все три поля проверяются по диапазону допустимых значений.Поле неделя недели на основе года проверяется от 1 до 53, что означает, что итоговая дата может быть в следующем году на основе недели к указанному.

В снисходительном режиме год идень недели проверяется по диапазону допустимых значений.Итоговая дата рассчитывается эквивалентно следующему трехэтапному подходу.Сначала создайте дату в первый день первой недели в запрашиваемом году на основе недели.Затем возьмите год недели, основанный на неделе, вычтите один и добавьте сумму в неделях к дате.Наконец, настройте правильный день недели в пределах локализованной недели.

Настройка этого экземпляра WeekFields зависит от локали и может иметь различные настройки в зависимости от нее, США и европейских стран.например, у Франции может быть другой день в качестве начала недели.

Например, DateFormatterBuilder в Java 8, создайте экземпляр синтаксического анализатора с языковым стандартом и используйте этот языковой стандарт для символа 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= (* 1043)*, en, es и т. Д.) Или принудительно установить язык во время вызова:

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 голосов
/ 31 декабря 2011

Формат Y, чтобы получить год недели, если календарь поддерживает год недели.(getCalendar().isWeekDateSupported())

1 голос
/ 06 ноября 2015

Я усвоил сложный путь к библиотеке тегов JSTL format:date с short, так как запрошенный формат использует YYYY под обложками.Который действительно может свернуть напечатанную дату вперед на год.

...