時刻
それでは次に進みましょう。date の次のエンティティは時刻であり、
LocalTimeクラスで表されます。典型的な例は、店舗の営業時間を表す、たとえば 7:00 から 23:00 までです。この時間に全国の店舗が開店しますが、実際の時間はタイムゾーンによって異なります。
LocalTime は、関連付けられた日付やタイム ゾーンを持たず、時刻のみを格納する値クラスです。期間を加算または減算すると、午前 0 時に切り取られます。つまり、20:00 プラス 6 時間は 2:00 です。
LocalTimeの使用は
LocalDateと似ています。 修飾子は
LocalTimeLocalTime time = LocalTime.of(20, 30); int hour = date.getHour(); // 20 int minute = date.getMinute(); // 30 time = time.withSecond(6); // 20:30:06 time = time.plusMinutes(3); // 20:33:06
で使用できますが、時間の操作は通常、修飾子が必要になるほど複雑ではありません。
日付と時刻を組み合わせる
次に見るクラスは
LocalDateTimeです。
この値クラスはLocalDateと
LocalTimeの組み合わせです。タイムゾーンなしで、日付と時刻の両方を表します。
LocalDateTime は、直接作成することも、日付と時刻を組み合わせて作成することもできます。3
LocalDateTime dt1 = LocalDateTime.of(2014, Month.JUNE, 10, 20, 30); LocalDateTime dt2 = LocalDateTime.of(date, time); LocalDateTime dt3 = date.atTime(20, 30); LocalDateTime dt4 = date.atTime(time);
番目と 4 番目のオプションでは、日付と時刻を柔軟に組み合わせる
atTime()メソッドを使用します。ほとんどの日付と時刻のシステム クラスには、オブジェクトを別のオブジェクトと組み合わせてより複雑なオブジェクトを作成するときに使用できる「at」メソッドがあります。
LocalDateTimeクラスの他のメソッドは、
LocalDateおよび
LocalTimeのメソッドと同様です。
同様のメソッド命名パターンにより、 APIの学習が容易になります。次の表には、関連するすべてのメソッド プレフィックスがリストされています。
インスタント
日付と時刻を扱うとき、私たちは通常、年、月、日、時、分、秒を扱います。しかし、これは「人間」と呼べる時間のモデルの一つにすぎません。一般的に使用される 2 番目のモデルは、「マシン」または「連続」時間です。このモデルでは、時間軸上の点は 1 つの大きな数字で表されます。
このアプローチは計算アルゴリズムを簡素化し、 Unixオペレーティング システムで時刻を保存するために使用されます。時刻は 1970 年 1 月 1 日から経過した秒数で表されます。同様に、
Javaでは、時間は 1970 年 1 月 1 日から経過したミリ秒数として保存されます。
java.time APIでの時間計算に対する機械的なアプローチは、
Instant value クラスによって提供されます。これにより、タイム ゾーンなどの付随情報をすべて持たずに、時間軸上の点を表すことができます。実際、このクラスには、1970 年 1 月 1 日の午前 0 時から経過したナノ秒数が含まれています。
Instant start = Instant.now(); // произведем вычисления Instant end = Instant.now(); assert end.isAfter(start); //машина времени не сработала
通常、
Instantクラスは、イベントがいつ発生したかを保存する必要があるが、イベントが発生したタイムゾーンは気にしない場合に、時点を保存および比較するために使用されます。
ほとんどの場合、 Instantクラスで何ができるかよりも、Instant クラスで何ができないかの方に興味があります。たとえば、次のコード行は例外をスローします。
インスタントオブジェクトはナノ秒数を格納するだけで、人間にとってより有用な時間単位を処理する機能を提供しないため、
instant.get(ChronoField.MONTH_OF_YEAR); instant.plus(6, ChronoUnit.YEARS);
例外が発生します。他の測定単位を使用するには、少なくともタイムゾーンを指定する必要があります。
時間帯
タイムゾーンの原理は、鉄道の発明と他の通信手段の改良により、人々が太陽時間の差が顕著になるほどの距離を移動できるようになったときにイギリスで発展しました。この時代まで、各村や都市は独自の時間に従って生活しており、その時間は日時計によって測定されることがほとんどでした。この写真は、これが引き起こした困難の一例を示しています。時計の赤い針はグリニッジ時間を示し、黒い針は 10 分異なる現地時間を示しています。タイムゾーン システムが開発され、現地の太陽時に置き換えられました
。しかし、重要な事実は、タイムゾーンは政治家によって作成され、地域に対する政治的支配を示すためによく使用されるということです。他のポリシーと同様、タイム ゾーンに関連するルールは論理に反することがよくあります。また、これらのルールは変更される可能性があり、警告なしに変更されることがよくあります。
タイム ゾーン ルールは、 IANAタイム ゾーン データベースを発行する国際グループによって編集されています。これには、地球の各地域の識別子と、その地域のタイムゾーン変更の履歴が含まれています。識別子は、
「Europe/London」または
「America/New_York」のようになります。
java.time APIがリリースされる前は、タイム ゾーンを表すために
TimeZoneクラスが使用されていました。
現在は代わりにZoneId が使用されます。それらの間には 2 つの重要な違いがあります。まず、
ZoneId は不変であるため、このクラスのオブジェクトを静的変数などに格納できるようになります。次に、ルール自体は
ZoneId自体ではなく、
ZoneRulesクラスに保存されます。ルールを取得するには、
ZoneIdクラス オブジェクトの
getRules()メソッドを呼び出す必要があります。
すべてのタイム ゾーンに共通する特徴は、 UTC/グリニッジからの固定オフセットです。最もよく使われるのは、「ニューヨークはロンドンより 5 時間遅れている」など、さまざまな都市間の時差について話すときにこれを使用することです。
ZoneOffsetクラスは
ZoneIdの子孫であり、ロンドンのグリニッジを通過する本初子午線との時差を表します。開発者の観点からすると、タイムゾーンとその複雑さに対処する必要がなくなるのは素晴らしいことです。
java.time API を使用すると、可能な限りこれを行うことができます。可能な限り、
LocalDate、LocalTime、LocalDateTime、および
Instantクラスを使用してください。タイムゾーンなしではできない場合は、
ZonedDateTimeクラスを使用します。
ZonedDateTimeクラス
日付と時刻を、カレンダーや時計で見られる人間の測定単位から機械単位に変換できます。その結果、
Localクラスまたは
Instant クラスから
ZonedTimeDateを作成できます。 タイム ゾーンの最も不快な機能の 1 つは、いわゆる夏時間です。夏時間のグリニッジとの切り替えに伴い、グリニッジとのタイムゾーンの差は年に 2 回 (またはそれ以上) 変化し、通常は春に増加し、秋に減少します。こうなると、家中の時計をすべて交換しなければなりません。
java.timeクラスでは、オフセット データは
「オフセット変換」として表されます。春には、これにより時間の「ギャップ」が発生し、一部の時間値が不可能になり、秋には逆に、一部の時間値が 2 回発生します。これらはすべて、
ZonedDateTimeクラスのファクトリ メソッドとコンバータ メソッドを通じてサポートされています。たとえば、1 日を追加すると論理日が追加され、夏時間に切り替えたり戻したりすると、24 時間より多くても少なくても表すことができます。
同様に、 atStartOfDay()メソッドは、1 日が真夜中に始まることを保証できないため、この名前が付けられています。夏時間に切り替えるときは、時差を考慮する必要があります。そして最後に夏時間に関するヒントを 1 つ。夏から冬への移行時の時間の重複 (同じ時間値が 2 回表示される場合) を考慮していることを証明したい場合は、そのような状況用に設計された 2 つの特別なメソッドのいずれかを使用できます。 これらのメソッドは、早い方または遅い方の時刻を返します。 value 、夏時間から冬時間への移行中にオブジェクトがオーバーラップに巻き込まれた場合。他のすべての状況では、戻り値は同じになります。
ZoneId zone = ZoneId.of("Europe/Paris"); LocalDate date = LocalDate.of(2014, Month.JUNE, 10); ZonedDateTime zdt1 = date.atStartOfDay(zone); Instant instant = Instant.now(); ZonedDateTime zdt2 = instant.atZone(zone);
zdt = zdt.withEarlierOffsetAtOverlap(); zdt = zdt.withLaterOffsetAtOverlap();
時間間隔
前に説明したすべてのクラスは、タイムライン上のポイントとして機能します。時間間隔を表すには、2 つの追加の値クラスが必要です。
Durationクラスは、秒とナノ秒で測定される時間の長さを表します。例:「23.6秒」
Periodクラスは、年、月、日で測定される期間を表します。例: 「3 年 2 か月と 6 日」これらの間隔は、日付または時刻に加算または減算できます。
Period sixMonths = Period.ofMonths(6); LocalDate date = LocalDate.now(); LocalDate future = date.plus(sixMonths);
フォーマットと解析
パッケージ全体は、日付と時刻 (
java.time.format )をフォーマットして表示するように設計されています。パッケージは、
DateTimeFormatterクラスとその
DateTimeFormatterBuilderファクトリを中心に展開します。フォーマッタを作成する最も一般的な方法は、次のような
DateTimeFormatterの静的メソッドと定数を使用する方法です。
- ISO_LOCAL_DATE など、ISO に記述されている一般的な形式の定数。
- ofPattern("dd/MM/uuuu") など、文字によって識別されるパターン。
- ofLocalizedDate(FormatStyle.MEDIUM) などのローカライズされたスタイル。
フォーマッタを作成したら、通常はそれを適切な日付クラス メソッドに渡して使用します。
DateTimeFormatter f = DateTimeFormatter.ofPattern("dd/MM/uuuu"); LocalDate date = LocalDate.parse("24/06/2014", f); String str = date.format(f);
これにより、日付出力の書式設定を担当するコードが別のクラスに分離されます。日付フォーマットのロケールを個別に指定する必要がある場合は、
withLocale(Locale)フォーマッタ メソッドを使用します。カレンダー、タイムゾーン、小数の入出力を担当するクラスにも同様のメソッドがあります。さらに微調整オプションが必要な場合は、
DateTimeFormatterBuilderクラスのドキュメントを参照してください。これにより、複雑なフォーマッタを段階的に作成できます。また、大文字と小文字を区別しないテキスト解析を設定したり、一部の解析エラーを無視したり、オフセットやオプションの要素を設定したりすることもできます。
結論
java.time API は、
Java SE 8で日付と時刻を操作するための新しい包括的なモデルです。
Joda-Timeのアイデアと実装を次のレベルに引き上げ、最終的に開発者が
java.util.Dateと
Calendarの使用を回避できるようにします。日付と時刻の操作が楽しくなりました。
原著
GO TO FULL VERSION