Y gibt 2012 zurück, während y 2011 in SimpleDateFormat zurückgibt


84

Ich frage mich, warum 'Y' 2012 zurückgibt, während 'y' 2011 zurückgibt in SimpleDateFormat:

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

Kann jemand erklären warum?


36
Nur als Hinweis für zukünftige Leser: Dieses Verhalten wird nur in der letzten Woche des Jahres oder in der ersten Woche des Jahres auftreten.
Ryvantage

Antworten:


89

Woche Jahr und Jahr. Aus Javadoc

Ein Wochenjahr ist mit einem WEEK_OF_YEAR-Zyklus synchronisiert. Alle Wochen zwischen der ersten und der letzten Woche (einschließlich) haben den gleichen Wochenjahreswert. Daher können der erste und der letzte Tag eines Wochenjahres unterschiedliche Kalenderjahreswerte haben.

Zum Beispiel ist der 1. Januar 1998 ein Donnerstag. Wenn getFirstDayOfWeek () MONTAG und getMinimalDaysInFirstWeek () 4 ist (ISO 8601-Standard-kompatible Einstellung), beginnt Woche 1 von 1998 am 29. Dezember 1997 und endet am 4. Januar 1998. Das Wochenjahr ist 1998 für die letzten drei Tage des Kalenderjahres 1997. Wenn jedoch getFirstDayOfWeek () SONNTAG ist, beginnt Woche 1 von 1998 am 4. Januar 1998 und endet am 10. Januar 1998; Die ersten drei Tage des Jahres 1998 sind dann Teil der 53. Woche von 1997 und ihr Wochenjahr ist 1997.


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 Einige Software ist verwirrt: strftimeBerechnet heute (29.12.2015) mit Woche 53 und Woche-Jahr als 2015.
aks

11

Hier ist ein Java 8-Update mit etwas Code, da GregorianCalendar wahrscheinlich veraltet oder aus zukünftigen JDK-Versionen entfernt wird.

Der neue Code wird in der WeekFieldsKlasse und speziell für Klein- y/ Großbuchstaben Ymit dem weekBasedYear()Feldzugriff behandelt.

Gibt ein Feld zurück, um auf das Jahr eines wochenbasierten Jahres zuzugreifen, das auf diesen WeekFields basiert. Dies ist das Konzept des Jahres, in dem Wochen an einem festen Wochentag wie Montag beginnen und jede Woche genau einem Jahr angehört. Dieses Feld wird normalerweise mit dayOfWeek () und weekOfWeekBasedYear () verwendet.

Woche eins (1) ist die Woche, die am getFirstDayOfWeek () beginnt, an dem es mindestens getMinimalDaysInFirstWeek () Tage im Jahr gibt. Somit kann die erste Woche vor Jahresbeginn beginnen. Wenn die erste Woche nach Jahresbeginn beginnt, liegt der vorherige Zeitraum in der letzten Woche des Vorjahres.

Dieses Feld kann mit jedem Kalendersystem verwendet werden.

In der Auflösungsphase des Parsens kann ein Datum aus einem wochenbasierten Jahr, einer Woche des Jahres und einem Wochentag erstellt werden.

Im strengen Modus werden alle drei Felder anhand ihres Bereichs gültiger Werte überprüft. Das Feld für die Woche des Jahres wird validiert, um sicherzustellen, dass das resultierende wochenbasierte Jahr das angeforderte wochenbasierte Jahr ist.

Im Smart-Modus werden alle drei Felder anhand ihres Gültigkeitsbereichs überprüft. Das Feld Woche für Woche basiert auf 1 bis 53, was bedeutet, dass das resultierende Datum im folgenden wochenbasierten Jahr bis zu dem angegebenen Datum liegen kann.

Im milden Modus werden das Jahr und der Wochentag anhand des Bereichs gültiger Werte validiert. Das resultierende Datum wird entsprechend dem folgenden dreistufigen Ansatz berechnet. Erstellen Sie zunächst ein Datum am ersten Tag der ersten Woche im angeforderten wochenbasierten Jahr. Nehmen Sie dann das wochenwochenbasierte Jahr, subtrahieren Sie eines und addieren Sie den Betrag in Wochen zum Datum. Stellen Sie schließlich den richtigen Wochentag innerhalb der lokalisierten Woche ein.

Die Einrichtung dieser WeekFieldsInstanz hängt vom Gebietsschema ab und kann je nach Gebietsschema unterschiedliche Einstellungen haben. US-amerikanische und europäische Länder wie Frankreich haben möglicherweise einen anderen Tag als Wochenbeginn.

DateFormatterBuilderInstanziieren Sie beispielsweise in Java 8 den Parser mit dem Gebietsschema und verwenden Sie dieses Gebietsschema für das YSymbol:

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

        ...
    }

    ...
}

Hier ist ein Beispiel

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

Und in Bezug des Lokals und das obere Gehäuse Y, können Sie entweder mit der Kommandozeilenoption spielen -Duser.language=( fr, en, es, usw.) oder zwingen , die locale beim Aufruf Zeit:

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

Format Y, um das Wochenjahr zu erhalten, wenn der Kalender das Wochenjahr unterstützt. ( getCalendar().isWeekDateSupported())


1

Ich habe gelernt , auf die harte Weise die JSTL - Tag - Bibliothek format:datemit shortals das angeforderte Format verwendet YYYY unter der Decke. Was in der Tat das Druckdatum um ein Jahr vorverlegen kann.


0

Ich konvertiere ein Datum hin und her - Sie würden das gleiche Jahr erwarten, wenn Sie dies tun.

Beachten Sie, wie es einen voranbringt!

Das ist schlecht: JJJJ! JJJJ

Sie können es hier ausführen .

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

Das ist gut: JJJJ

JJJJ

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.