Y возвращает 2012, а y возвращает 2011 в SimpleDateFormat


85

Интересно, почему '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

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


40
В качестве примечания для будущих читателей: такое поведение будет происходить только в последнюю неделю года или первую неделю года.
ryvantage 05

Ответы:


94

неделя год и год. Из javadoc

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

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


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 Некоторое программное обеспечение сбивает с толку: strftimeсегодня (29.12.2015) вычисляется как неделя 53, а неделя-год - как 2015.
aks

11

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

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

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

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

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

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

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

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

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

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

Например, DateFormatterBuilderJava 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=( fr, 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

Отформатируйте год Yнедели, если календарь поддерживает год недели. ( getCalendar().isWeekDateSupported())


0

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


0

Я конвертирую дату туда и обратно - вы ожидаете того же года, когда вы это делаете.

Обратите внимание, как он продвигается вперед!

Это плохо: ГГГГ! ГГГГ

Вы можете запустить его здесь .

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

Это хорошо: гггг

гггг

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.