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

Хтось може пояснити, чому?


36
Просто як примітка для майбутніх читачів: така поведінка відбуватиметься лише протягом останнього тижня року чи першого тижня року.
ryvantage

Відповіді:


90

тиждень рік і рік. З javadoc

Рік тижня синхронізується із циклом WEEK_OF_YEAR. Усі тижні між першим та останнім тижнями (включно) мають однакове значення тижня в році. Отже, перший та останній дні тижня року можуть мати різні значення календарного року.

Наприклад, 1 січня 1998 року - четвер. Якщо getFirstDayOfWeek () має ПОНЕДІЛОК, а getMinimalDaysInFirstWeek () дорівнює 4 (стандартна сумісна установка ISO 8601), то 1 тиждень 1998 року починається 29 грудня 1997 року і закінчується 4 січня 1998 року. Тиждень - 1998 рік за останні три дні календарного 1997 року. Якщо, однак, getFirstDayOfWeek () - НЕДІЛЯ, то 1 тиждень 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обчислює сьогодні (12/29/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())


1

Я дізнався , Важкий шлях до 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.