web-dev-qa-db-ja.com

Java.timeで数分または数時間の期間を取得できないのはなぜですか?

Duration の新しいクラス JSR 31 date API( Java.time package )はJava 8以降、javadocは次のように述べています。

このクラスは、秒またはナノ秒の観点から量または時間をモデル化します。 分や時間などの他の期間ベースの単位を使用してアクセスできますさらに、DAYS単位を使用でき、まったく同じものとして扱われます24時間まで、したがって夏時間の影響を無視します。

では、なぜ次のコードがクラッシュするのですか?

Duration duration = Duration.ofSeconds(3000);
System.out.println(duration.get(ChronoUnit.MINUTES));

これはUnsupportedTemporalTypeExceptionを発生させます:

Java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Minutes
    at Java.time.Duration.get(Duration.Java:537)

それでは、期間オブジェクトから分と時間を抽出する推奨される方法は何ですか?秒数から計算する必要がありますか?なぜそのように実装されたのですか?

50
Pierre Henry

「なぜそのように実装されたのですか?」

他の答えは、時間/分を照会できるtoXxx()メソッドに関するものです。私はその理由に対処しようとします。

TemporalAmountインターフェースとget(TemporalUnit)メソッドは、プロセスのかなり後期に追加されました。私は個人的に、その領域で設計を行うための正しい方法の十分な証拠があるとは完全に確信していませんでしたが、TemporalAmountを追加するためにわずかにひねりました。そうすることで、APIを少し混乱させたと思います。

後から考えると、TemporalAmountには適切なメソッドが含まれていると思いますが、get(TemporalUnit)には別のメソッド名が付いているはずです。理由は、get(TemporalUnit)は本質的にフレームワークレベルのメソッドであり、日常的に使用するために設計されていないためです。残念ながら、メソッド名getはこれを意味しないため、Durationget(ChronoUnit.MINUTES)を呼び出すようなバグが発生します。

したがって、get(TemporalUnit)を考える方法は、量を_Map<TemporalUnit, Long>_として表示する低レベルのフレームワークを想像することです。ここで、Durationはサイズ2のMapですSECONDSおよびNANOSのキーを使用します。

同様に、Periodは、低レベルのフレームワークから、サイズ3のMapとして表示されます-DAYSMONTHS、およびYEARS(幸いなことにエラーの可能性は低くなります)。

全体として、アプリケーションコードの最善のアドバイスは、メソッドget(TemporalUnit)を無視することです。代わりにgetSeconds()getNano()toHours()およびtoMinutes()を使用してください。

最後に、Durationから "hh:mm:ss"を取得する1つの方法は次のとおりです。

_LocalTime.MIDNIGHT.plus(duration).format(DateTimeFormatter.ofPattern("HH:mm:ss"))
_

まったくきれいではありませんが、1日未満の期間は機能します。

Java 9の新しい_to…Part_メソッド

JDK-8142936 問題がJava 9で実装されました。Durationの各部分にアクセスする次のメソッドを追加します。

  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart
66
JodaStephen

ドキュメント の意味:

これは、サポートされる2つのユニット、SECONDSおよびNANOSのそれぞれの値を返します。他のすべてのユニットは例外をスローします。

だから、最善の推測の答え-それは彼らがそれを設計した方法です。

hours で取得するには、他のメソッドのいくつかを使用できます。

long hours = duration.toHours();

または

long minutes = duration.toMinutes();
28
blgt

便利なtoHourstoMinutesおよびその他の変換方法を指摘したbigtの回答(+1)に追加したいと思います。 期間指定 の意味:

このクラスは、秒またはナノ秒の観点から量または時間をモデル化します。 [...]

期間の範囲には、長い数値より大きな数値を格納する必要があります。これを実現するために、クラスは秒を表すlongとナノ秒を表すintを格納します。これは常に0〜999,999,999です。

getSecondsgetNanoget(TemporalUnit)など、さまざまなgetterメソッドがあります。期間が(秒、ナノ)のペアとして表されることを考えると、get(TemporalUnit)が秒とナノに制限される理由は明らかです。これらのゲッターメソッドは期間インスタンスから直接データを抽出し、ロスレスです。

対照的に、toDaystoHourstoMillistoMinutes、およびtoNanosを含むさまざまなtoメソッドがあります期間値の変換。これらの変換は、データの切り捨てを伴うという点で損失が大きく、要求された形式で期間値を表現できない場合は例外をスローする可能性があります。

Getメソッドが変換なしでデータを抽出し、toメソッドが何らかの変換を実行することは、明らかに設計の一部です。

8
Stuart Marks

「正規化された」方法で時間/分/秒コンポーネントを取得するには、それらを手動で計算する必要があります-以下のコードは基本的にDuration#toString 方法:

Duration duration = Duration.ofSeconds(3000);
long hours = duration.toHours();
int minutes = (int) ((duration.getSeconds() % (60 * 60)) / 60);
int seconds = (int) (duration.getSeconds() % 60);
System.out.println(hours + ":" + minutes + ":" + seconds);
7
assylias

Hourseを削除してから分を取得

long hours = attendanceDuration.toHours(); long minutes = attendanceDuration.minusHours(hours).toMinutes();

1
user9078671