web-dev-qa-db-ja.com

Java "week year"は実際どのように機能しますか?

これは単純なエラーとして始まりました。YYYYオブジェクトのフォーマット文字列にyyyyではなくSimpleDateFormatがありました。しかし、誤ったフォーマット文字列を使用したテストの結果には完全に困惑しています。

このコード:

@Test
public void whatTheHell() {
        try {
                SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY");

                Date d1 = sdf.parse("01/07/2016");
                Date d2 = sdf.parse("02/08/2016");
                Date d3 = sdf.parse("11/29/2027");

                System.out.println(d1.toString());
                System.out.println(d2.toString());
                System.out.println(d3.toString());
        } catch (ParseException pe) {
                fail("ParseException: " + pe.getMessage());
        }
}

この出力を生成します:

Sun Dec 27 00:00:00 PST 2015
Sun Dec 27 00:00:00 PST 2015
Sun Dec 27 00:00:00 PST 2026

ここで「Y」パラメータに関するドキュメントを読みました: https://docs.Oracle.com/javase/7/docs/api/Java/util/GregorianCalendar.html ですが、それでも私はここで機能しているロジックを見ることができません。特に最後の例:1月の日付(おそらく2月)が前年の12月にどのように変換されるのかが少しわかりますが、11月29日の日付を11か月後ろに移動すると、困惑します。そして、12月27日の何がそれほど特別なのでしょうか。

誰か説明できますか?

詳細情報

@Janは、toString()メソッドに依存することが問題になる可能性があることを示唆したので、印刷する日付形式を定義しましたYYYY MM dd '-' yyyy MM dd上記と同じコードで。追加の出力は次のとおりです。

2016 12 27 - 2015 12 27
2016 12 27 - 2015 12 27
2027 12 27 - 2026 12 27
22
Dave Mulligan

簡単です。2015年12月27日は、2016年の週の1週目の1日目です(2026年12月27日は、2027年の週の1週目の1日目です)。これは、次の行を追加することで確認できます。

SimpleDateFormat odf = new SimpleDateFormat("YYYY-ww-u");
System.out.println(odf.format(d1));
System.out.println(odf.format(d2));
System.out.println(odf.format(d3));

SimpleDateFormatが日付を出力する場合、年、月、日、曜日、週、週、年などのすべてのフィールドを使用できます。

解析時に、SimpleDateFormatは一致する値のセットを期待します:日、月、年または曜日、年の週、週-年。週年を指定したが、曜日と年の週を指定しなかったため、これらの値は1と見なされています。


実際の値は、ロケールによって異なります。

  • 年のどの週が第1週か
  • 週の最初の日

https://docs.Oracle.com/javase/7/docs/api/Java/util/GregorianCalendar.html#week_and_year を参照)

私のシステムでは(de-chロケールを使用し、「EEE MMM dd HH:mm:ss zzz yyyy-YYYY-ww-u」という形式で)取得します

Mo Jan 04 00:00:00 MEZ 2016-2016-01-1 
 Mo Jan 04 00:00:00 MEZ 2016-2016-01-1 
 Mo Jan 04 00:00:00 MEZ 2027-2027-01-1
10
Thomas Kläger

定義は異なります

1週間はさまざまな方法で定義できます。たとえば、米国では、週の最初の日が最も頻繁に日曜日であると見なされますが、ヨーロッパおよび他の多くの場所では、最初の日は月曜日です。

同様に、週ベースの年の週もさまざまな方法で定義できます。

  • 1週目は1月1日です。
  • 第1週は、日曜日などの特定の曜日を含む最初の週です。
  • 第1週は、前年の日付を含まず、新年の日のみを含む最初の週です。
  • … もっと

使用しているレガシークラスは、Localeで指定された定義を暗黙的に使用します。適用されるロケールも暗黙的であり、特に指定しない限り、JVMの現在のデフォルトLocaleが使用されます。

週の定義の難しさに関するさらに興味深い詳細については、この質問を参照してください JVM 8とJVM 10でのWeekFieldsの異なる動作

ISO 8601

日時処理には実用的な国際標準 ISO 8601 があります。

ISO 8601の週の定義 は次のとおりです。

  • 週は月曜日から始まります
  • 1週目は、その年の最初の木曜日です。
  • 1年は52週間または53週間で構成されます。
  • 1年は、前の暦年から、および次の暦年からも1日以上ある場合があります。

可能な限り、ISO 8601標準定義を使用することをお勧めします。この標準定義はシンプルで論理的であり、業界全体で採用が増加しています。

Java.time

Java.timeクラスは、 WeekFields クラスで週ベースの年の週をサポートします。

LocalDate ld = LocalDate.of( 2019 , Month.JANUARY , 1 ) ;
long week = ld.get( WeekFields.ISO.weekOfWeekBasedYear() ) ;

この IdeOne.comでライブで実行されるコード を参照してください。

ld.toString():2019-01-01

1週目

org.threeten.extra.YearWeek

ただし、この作業の多くを行う場合は、 ThreeTen-Extra ライブラリをプロジェクトに追加することをお勧めします。 YearWeek クラスが参考になります。このクラスは、その週の任意の日のLocalDateの生成など、いくつかの便利なメソッドを提供します。

LocalDate ld = LocalDate.of ( 2019 , Month.JANUARY , 1 );
YearWeek yw = YearWeek.from ( ld );
LocalDate startOfWeek = yw.atDay ( DayOfWeek.MONDAY );

ld.toString():2019-01-01

yw.toString():2019-W01

startOfWeek.toString():2018-12-31

2019年の週ベースの年の最初の日が、2019年ではなく、前の暦年2018年からの日付であることに注意してください。

 calendar for month of January 2019, with week number, showing first week starts in the previous calendar year on 2018-12-31 


Java.timeについて

Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、厄介な古い レガシー 日時に取って代わります Java.util.DateCalendar 、& SimpleDateFormat などのクラス。

詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 310 です。

Joda-Time プロジェクトは、現在 メンテナンスモード で、 Java.time クラスへの移行を推奨しています。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠した JDBCドライバー を使用します。文字列やJava.sql.*クラスは必要ありません。

Java.timeクラスはどこで入手できますか?

5
Basil Bourque