SimpleDateFormatでYは2012を返し、yは2011を返します


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 2014年

回答:


91

週年と年。javadocから

1週間は、WEEK_OF_YEARサイクルと同期しています。最初の週と最後の週(両端を含む)の間のすべての週の週の年の値は同じです。したがって、週の最初と最後の日は、暦年の値が異なる場合があります。

たとえば、1998年1月1日は木曜日です。getFirstDayOfWeek()がMONDAYで、getMinimalDaysInFirstWeek()が4(ISO 8601標準互換設定)の場合、1998年の第1週は1997年12月29日に始まり、1998年1月4日に終わります。過去3日間の週年は1998年です。ただし、getFirstDayOfWeek()がSUNDAYの場合、1998年の第1週は、1998年1月4日に始まり、1998年1月10日に終わります。1998年の最初の3日間は、1997年の第53週の一部であり、その週の年は1997年です。


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 一部のソフトウェアが混乱しています。strftime今日(2015
aks

11

これは、GregorianCalendarが非推奨になるか、将来のJDKバージョンから削除される可能性があるため、いくつかのコードを含むJava8アップデートです。

新しいコードはWeekFieldsクラスで処理され、特にフィールドアクセサーを使用して小文字y/大文字で処理さYweekBasedYear()ます。

このWeekFieldsに基づいて、週ベースの年にアクセスするためのフィールドを返します。これは、週が月曜日などの固定された曜日に始まり、各週が正確に1年に属する年の概念を表します。このフィールドは通常、dayOfWeek()およびweekOfWeekBasedYear()で使用されます。

第1週(1)は、getFirstDayOfWeek()で始まる週であり、その年には少なくともgetMinimalDaysInFirstWeek()日があります。 したがって、第1週は、年の初めの前に開始できます。最初の週が年の初めの後に始まる場合、前の期間は前年の最後の週になります。

このフィールドは、任意のカレンダーシステムで使用できます。

解析の解決フェーズでは、週ベースの年、週、曜日から日付を作成できます。

厳密モードでは、3つのフィールドすべてが有効な値の範囲に対して検証されます。週ベースのフィールドは、結果の週ベースの年が要求された週ベースの年であることを確認するために検証されます。

スマートモードでは、3つのフィールドすべてが有効な値の範囲に対して検証されます。週ベースの年フィールドは1から53まで検証されます。つまり、結果の日付は、指定された次の週ベースの年になる可能性があります。

寛容モードでは、年と曜日が有効な値の範囲に対して検証されます。結果の日付は、次の3段階のアプローチと同等に計算されます。まず、要求された週ベースの年の最初の週の最初の日に日付を作成します。次に、週ベースの年を取得し、1を減算して、日付に週単位の金額を加算します。最後に、ローカライズされた週内の正しい曜日に調整します。

これのセットアップ 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=frenes、など)、または起動時にロケールを強制的に:

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

要求された形式が内部でYYYYを使用するため、JSTLタグライブラリformat:dateshort使用する難しい方法を学びました。これは確かに印刷された日付を1年先に進めることができます。


0

私は日付を前後に変換します-これを行うと同じ年になると予想されます。

それがどのように進歩するかに注目してください!

これは悪いです:YYYY! YYYY

ここで実行できます

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

これは良いです:yyyy

yyyy

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.