JavaRush /Java Blog /Random-JA /時刻と日付を操作するための直感的で堅牢なライブラリが、ついに Java で利用可能になりました (パート 1)。
theGrass
レベル 24
Саратов

時刻と日付を操作するための直感的で堅牢なライブラリが、ついに Java で利用可能になりました (パート 1)。

Random-JA グループに公開済み
Java は     ついに、日付と時刻を操作する直観的で信頼性の高い方法を手に入れました。日付と時刻の原則は、多くのアプリケーションの基本です。誕生日、レンタル日、イベント時間、店舗の営業時間などのさまざまな情報はすべて日付と時刻に基づいていますが、Java SE ではそれらを操作する便利な方法が提供されていませんでした。Java SE 8以降、日付と時刻を操作するための適切に構造化されたAPIを提供するjava.timeパッケージのセットがありました。
背景
Java が初めて登場したバージョン1.0     では、日付と時刻を操作する唯一のクラスはjava.util.Dateでした。開発者が最初に気づいたのは、これが「日付」を表していないということでした。実際、これは 1970 年 1 月 1 日から測定されたミリ秒単位の精度で、ある時点を表します。しかし、一部の開発者は、 DatetoString()メソッドがマシンのJava設定で指定されたタイム ゾーンで日付と時刻を表示するという事実に基づいて、Date がタイム ゾーンで動作できると誤って結論付けました。このクラスを修正するのは非常に困難 (または非常に怠惰) であることが判明したため、バージョン1.1では新しいクラスjava.util.Calendarを追加する必要がありました。残念ながら、CalendarクラスはDateよりもそれほど優れているわけではないことが判明しました。 以下に、その実装における既存の問題の小さなリストを示します。
  • 変更可能。日付や時刻などのクラスは不変である必要があります。
  • オフセット。Date の年は 1900 年から始まり、両方のクラスの月は 0 から始まります。
  • 名前。Date は実際には「日付」ではなく、Calendar はカレンダーではありません。
  • フォーマット中。書式設定はカレンダーではなく日付でのみ機能し、スレッドセーフではありません。
    2001 年に、 Joda-Timeプロジェクトが作成されました。 彼の目標は単純で、 Javaで日付と時刻を扱うための高品質なライブラリを作成することでした。 時間はかかりましたが、最終的にバージョン1.0がリリースされ、すぐに非常に人気があり、広く使用されるようになりました。時間が経つにつれて、開発者は同様の利便性を備えたライブラリを JDKの一部として提供することを求めるようになりました。 ブラジルの Michael Nascimento Santos 氏の参加により、 JSR-310プロジェクトが開始されました。これは、 JDKで日付と時刻を操作するための新しい API を作成および統合するための公式プロセスです。
レビュー
新しい java.time API には 5 つのパッケージが含まれています。
  • java.time - 値を保存するオブジェクトを含む基本パッケージ
  • java.time.chrono - さまざまなカレンダーへのアクセスを提供します
  • java.time.format - 日付と時刻のフォーマットと認識
  • java.time.temporal - 低レベルのライブラリと高度な機能
  • java.time.zone - タイムゾーンを操作するためのクラス
    ほとんどの開発者は主に基本パッケージとフォーマットを使用し、おそらく java.time.temporal を使用します。したがって、68 の新しいタイプが追加されたとしても、開発者が使用するのはそのうちの約 3 分の 1 だけです。
日付
LocalDate     クラスは、新しい APIで最も重要なクラスの 1 つです。日付を表す不変の値が含まれます。時刻やタイムゾーンの設定はできません。「ローカル」という名前は Joda-Timeでよく知られているかもしれませんが、もともとは ISO-8601標準に由来しています。それは正確にはタイムゾーンがないことを意味します。基本的に、 LocalDate は「2014 年 4 月 5 日」などの日付の説明です。この日付の実際の時刻は、タイムゾーンによって異なります。たとえば、オーストラリアでは、この日付はロンドンより 10 時間早く、サンフランシスコより 18 時間早くなります。 LocalDateクラスには、一般的に必要なメソッドがすべて含まれています。 LocalDate date = LocalDate.of(2014, Month.JUNE, 10); int year = date.getYear(); // 2014 Month month = date.getMonth(); // Июнь int dom = date.getDayOfMonth(); // 10 DayOfWeek dow = date.getDayOfWeek(); // Вторник int len = date.lengthOfMonth(); // 30 (дней в Июне) boolean leap = date.isLeapYear(); // false (не високосный год)     この例では、ファクトリ メソッドを使用して作成された日付が表示されます (すべてのコンストラクターはプライベートです)。次に、オブジェクトにデータを要求します。 Monthおよび DayOfWeek列挙は、コードをより読みやすく信頼性を高めるために設計されていることに注意してください。次の例では、日付を変更する方法を示します。クラスは不変であるため、結果は新しいオブジェクトになりますが、元のオブジェクトはそのまま残ります。 LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.withYear(2015); // 2015-06-10 date = date.plusMonths(2); // 2015-08-10 date = date.minusDays(1); // 2015-08-09     これらは比較的単純な変更ですが、多くの場合、より複雑な日付の変更が必要になります。 java.time APIには、これを行うための特別なメカニズムである TemporalAdjuster があります。その目的は、月の最終日に対応するオブジェクトを取得するなど、日付を操作できる組み込みツールを提供することです。それらの一部は APIに含まれていますが、独自のものを追加することもできます。修飾子の使用は非常に簡単ですが、静的インポートが必要です。 import static java.time.DayOfWeek.* import static java.time.temporal.TemporalAdjusters.* LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.with(lastDayOfMonth()); date = date.with(nextOrSame(WEDNESDAY));     修飾子を使用すると、コードが大幅に簡素化されます。手動による日付操作が大量に行われることを誰も望んでいません。プロジェクト内で何らかの日付操作が何度も発生する場合は、独自の修飾子を作成すると、チームはそれをすでに作成されテストされたコンポーネントとして使用できます。
値としての時刻と日付
LocalDate が値     である理由を理解するために、少し時間を費やす価値があります。値は完全に交換可能な単純なデータ型であり、値が等しい場合、オブジェクトの同一性は無意味になります。値クラスの典型的な例は Stringです。私たちは、 equals()を使用して文字列を比較しますが、 ==演算子と比較したときにオブジェクトが同一であるかどうかは気にしません。日付と時刻を扱うクラスのほとんども値です。したがって、ドキュメントに記載されているように、 ==演算子を使用してそれらを比較することは悪い考えです。さらに詳しく知りたい方は、私の最近の VALJO の 定義を参照してください。これは、不変性、ファクトリ メソッド、 equals()hashCodetoString()の適切な定義など、 Javaの値オブジェクトが従わなければならない厳密なルール セットを概説しています。そして、 compareTo . () .
代替カレンダー
LocalDate     クラスは、 java.timeのすべての主要クラスと同様に、 ISO-8601標準で説明されているように、単一のカレンダーにバインドされています。標準 8601 は、グレゴリオ暦としても知られる世界標準の暦を記述しています。標準年には 365 日が含まれ、閏年は 366 日です。100 で割り切れない限り、または 400 で割り切れない限り、4 年ごとが閏年となります。計算を容易にするために、新しい元号の最初の年の前年はゼロとみなされます。これがデフォルトのシステムであることの最初の結果は、結果が GregorianCalendarを使用して計算された結果と必ずしも一致するとは限らないことです。 GregorianCalendarクラスには、1582 年 10 月 15 日より前のすべての日付をユリウス暦に切り替える機能が組み込まれています。ユリウス暦では、例外なく 4 年ごとにうるう年がありました。問題は、あるシステムから別のシステムへの移行は歴史的事実であるのに、なぜ java.time がそれをモデル化しないのかということです。はい、各国が異なる時期にグレゴリオ暦に切り替えたため、バチカン移行日のみを考慮すると、他のほとんどの国については不正確なデータが得られることになります。たとえば、北米の植民地を含む大英帝国は、ほぼ 200 年後の 1752 年 9 月 14 日にグレゴリオ暦に切り替えました。ロシアは 1918 年 2 月 14 日まで暦を変更しなかったが、スウェーデンの移行は一般に不透明な問題である。その結果、1918 年より前の日付の実際の意味は状況によって大きく異なります。 LocalDateコードの作成者は、不一致を避けるために、ユリウス暦からグレゴリオ暦への移行をまったくモデル化しないという完全に合理的な決定を下しました。 すべてのコア クラスでISO-8601 をデフォルトのカレンダーとして使用することの 2 番目の結果は、残りのカレンダーを処理するために追加のクラスのセットが必要になることです。 Chronologyインターフェイスは代替カレンダーを操作するための基礎であり、ロケール名で目的のカレンダーを見つけることができます。 Java 8には、タイ仏教、明国 (台湾)、日本、イスラムの 4 つの追加カレンダーが付属しています。他のカレンダーにはプログラムが付属している場合があります。 各カレンダーには、 ThaiBuddhistDateMinguoDateJapaneseDateHijrahDateなどの特別な日付クラスがあります。日本政府向けなど、非常にローカライズされたアプリケーションでこれらを使用することは理にかなっています。追加のインターフェイス ChronoLocalDate は、 LocalDateとともに上記の 4 つのクラスのコア抽象化として使用されます。 を使用すると、使用するカレンダーの種類に関係なくコードを作成できます。この抽象化は存在しますが、その使用はお勧めできません。 この抽象化が推奨されない理由を理解することは、 java.time API全体がどのように機能するかを理解するために重要です。結論としては、特定のカレンダーを参照せずに記述されたコードのほとんどは機能しないことが判明するということです。たとえば、1 年が 12 か月であるかどうかはわかりませんが、開発者によっては 12 か月を足して 1 年を足したと考える人もいます。すべての月の日数がほぼ同じかどうかはわかりません。コプト暦では 30 日で 12 か月、5 ~ 6 日で 1 か月になります。また、日本の暦では次の天皇の宣言から年が数えられるため、来年の数字が現在の年より 1 増えるとは限りません (この場合、同じ月の 2 日でも)。異なる年に属することもできます)。複数のカレンダーを同時に操作できる高品質で実用的なコードを作成する唯一の方法は、日付と時刻に関するすべての操作を実行するコードのコアを、標準カレンダーを使用して、日付の入力/出力の場合にのみ作成する必要があることです。他の暦法に変換する必要があります。つまり、アプリケーション内のストレージとすべての日付操作には LocalDateを使用することをお勧めします。 また、入力日付と出力日付をローカライズする場合にのみ、 ChronoLocalDateを使用する必要があります。これは通常、ユーザー プロファイルに保存されているカレンダー クラスから取得されます。確かに、ほとんどのアプリケーションでは、それほど深刻なローカライゼーションは必要ありません。 この章で説明されているすべての詳細についての説明が必要な場合は、 ChronoLocalDateクラスの ドキュメントへようこそ。      記事の続き 元の記事     
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION