14

これらは、パッケージ内の 2 つのフィールドjava.time.temporalです。

IsoFields.WEEK_BASED_YEAR

WeekFields.ISO.weekBasedYear()

ISO-8601 では、他の 2 種類の日付、つまり通常の暦日 (年、月、日で構成される) と序数の日付 (年と日で構成される) に加えて、いわゆる週の日付を定義しています。 )。曜日は YYYY-'W'ww-e の形式で定義されます。w は年の週を表し、e は数値の ISO 曜日を表します。Y は週ベースの年を表し、週ベースの年は最終的に前の年に開始できる週サイクルにバインドされるため、暦年の開始時または終了時を除き、暦年と同じです。週の日付がどのように形成されるかを理解するには、次の 2 つの規則が重要です。

  1. 週は常に月曜日から始まります。
  2. 暦年の最初の週は、少なくとも 4 日を含む週です。

ISO-8601 では 1 種類の週ベースの年しか言及されていないため、一見すると、両方の JSR-310 フィールドは同じように見えます。しかし、待って、驚いてください。次のコード例を考えてみましょう。

LocalDate date1 = 
  LocalDate.of(2000, 2, 29).with(IsoFields.WEEK_BASED_YEAR, 2014);
System.out.println("IsoFields-Test: " + date1); // output: 2014-03-01

LocalDate date2 = 
  LocalDate.of(2000, 2, 29).with(WeekFields.ISO.weekBasedYear(), 2014);
System.out.println("WeekFields-Test: " + date2); // output: 2014-02-25

私は2番目のバリエーションをよく理解していますが、クラス名に「公式の」ISO-8601参照を使用している最初の日付の結果が異なることに本当に驚いています。計算結果を説明するには:

日付 2000-02-29 は ISO-weekdate-notation の 2000-W09-2 に対応し、2014-02-25 は 2014-W09-2 に対応し、週と曜日を保持します。ここまでは順調。小さいフィールドの特性を保持するこのルールは、暦年を変更する方法と似ています (ほとんどの場合、暦日の月と日は変更されません)。

しかし、2014-03-01 の結果はどうでしょうか? ここでは、「月の日」フィールドの違い (29 対 25) を考慮に入れるために、アルゴリズムは対応する週の日付に 4 日を単純に追加しています。この動作に関するソースや公式ドキュメントは見つかりませんでした。これら 2 つの分野の違いの正当な理由がどこにあるのか知っている人はいますか? アルゴリズムの動作に関するドキュメントはありますか?

アップデート:

ここで、2 つのフィールドのどちらがより適切にサポートされているかを調べるために、次の式を使用して新しい API の一貫性をテストしようとしました。

System.out.println(
  "14 week-based-years later = "
  + LocalDate.of(2000, 2, 29).plus(14, IsoFields.WEEK_BASED_YEARS));

出力は 2014-03-01 で説明されている のケースと同様ですがIsoFields.WEEK_BASED_YEAR、結果 2014-02-25 (=2014-W09-2) の方がはるかに論理的です。これまでのところ、この一時的な単位はクラスにもあるIsoFieldsため、動作はクラス内で一貫していますIsoFields。文書化されておらず、直感的でない「機能」のように見えます。

私はバージョンを使用しています: java.runtime.version=1.8.0-b132

その他のテスト:

LocalDate d = LocalDate.of(2014, 3, 1); // 2014-W09-6
System.out.println(
  "week-of-year in 2014-03-01: " 
  + d.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
System.out.println(
  "day-of-week in 2014-03-01: " 
  + d.get(ChronoField.DAY_OF_WEEK));

LocalDate later = d.plus(14, IsoFields.WEEK_BASED_YEARS); // 2028-03-02 = 2028-W09-4
System.out.println(
  "14 week-based-years later = " 
  + later);
System.out.println(
  "week-of-year in " + later + ": " 
  + later.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
System.out.println(
  "day-of-week in " + later + ": " 
  + later.get(ChronoField.DAY_OF_WEEK));

出力:

week-of-year in 2014-03-01: 9
day-of-week in 2014-03-01: 6
14 week-based-years later = 2028-03-02
week-of-year in 2028-03-02: 9
day-of-week in 2028-03-02: 4

明確なルールは認識していません。14 週ベースの年を追加する間、曜日も月の日も保持されません。これは追加の質問です: 背後にあるルールは何IsoFields.WEEK_BASED_YEARSですか? JSR-310 チームが私たちを啓発してくれるのではないでしょうか?

4

1 に答える 1

8

IsoFieldsこれは、このメソッドがテストされていないためにすり抜けてしまったバグです(申し訳ありません)。正しく実装されている場合、IsoFieldsとの間には目に見える違いはほとんどないはずです。WeekFields.ISO

最終的にシステム全体で機能し、修正されるバグ レポートとパッチを参照してください。

テストにより、フィールドの取得に問題がないことが明らかになりました。バグは のwith/adjustIntoメソッドにのみ影響を与えましたWEEK_BASED_YEARWEEK_BASED_YEARS壊れた を再利用して内部的に追加が実装されているため、ユニットが影響を受けWEEK_BASED_YEARます。

2014 年 8 月 28 日の更新: これは 8u20 で修正された 14 個の java.time バグの 1 つです

于 2014-04-12T14:05:04.373 に答える