これは単純なエラーとして始まりました。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
簡単です。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と見なされています。
実際の値は、ロケールによって異なります。
( 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
1週間はさまざまな方法で定義できます。たとえば、米国では、週の最初の日が最も頻繁に日曜日であると見なされますが、ヨーロッパおよび他の多くの場所では、最初の日は月曜日です。
同様に、週ベースの年の週もさまざまな方法で定義できます。
使用しているレガシークラスは、Locale
で指定された定義を暗黙的に使用します。適用されるロケールも暗黙的であり、特に指定しない限り、JVMの現在のデフォルトLocale
が使用されます。
週の定義の難しさに関するさらに興味深い詳細については、この質問を参照してください JVM 8とJVM 10でのWeekFieldsの異なる動作
日時処理には実用的な国際標準 ISO 8601 があります。
ISO 8601の週の定義 は次のとおりです。
可能な限り、ISO 8601標準定義を使用することをお勧めします。この標準定義はシンプルで論理的であり、業界全体で採用が増加しています。
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年からの日付であることに注意してください。
Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、厄介な古い レガシー 日時に取って代わります Java.util.Date
、 Calendar
、& SimpleDateFormat
などのクラス。
詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 310 です。
Joda-Time プロジェクトは、現在 メンテナンスモード で、 Java.time クラスへの移行を推奨しています。
Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠した JDBCドライバー を使用します。文字列やJava.sql.*
クラスは必要ありません。
Java.timeクラスはどこで入手できますか?