今回のボツ原稿は和暦を扱うJapaneseDate
クラスと各地の時差を反映した時刻を扱うZonedDateTime
についてです。
P.89に5.1.8として続く想定です。
和暦の扱い
日付を扱えるようになると、元号を含んだ日付も扱いたいですよね。 java.time.chrono.JapaneseDate
クラスで和暦を扱うことができます。
ではJapaneseDate
クラスを使って、元号の付いた日付を表示してみましょう。
JapaneseDate.now()
を実行してみます。このとき、新たなimport
が必要になりますが、自分で入力せずにJShellの補完機能を使ってみます。
JapaneseDate
と入力した状態で[Shift]+[Tab]を押したあと、[i]キーを押します。
jshell> JapaneseDate 0: 何もしない 1: import: java.time.chrono.JapaneseDate 選択:
選択肢が表示されるので、ここで[1]キーを押してみます。 「imported」と表示されて次のようになったはずです。
Imported: java.time.chrono.JapaneseDate jshell> JapaneseDate
これはimport java.time.chrono.JapaneseDate
を実行したのと同じ効果があります。ここで先ほどと違い*
ではなくJapaneseDate
クラスを指定しているので、java.time.chrono
パッケージの中のJapaneseDate
クラスだけパッケージ名を省略できるようになります。
続きの.now()
を入力して実行してみましょう。
jshell> JapaneseDate.now() $20 ==> Japanese Reiwa 3-06-18
「Reiwa」と表示されて和暦での年が表示されました。
サブパッケージ
ところで、JapaneseDate
クラスが所属しているjava.time.chrono
パッケージは、java.time
パッケージに対して「サブパッケージ」という関係になっています。
すでにjava.time.*
に対してimportを行っているのでchrono.JapaneseDate
と入力できそうですが、残念ながらそれはできません。サブパッケージは、プログラムから見たときの特別扱いは何もないので、利用するときは名前の前半がかぶってる全く別のパッケージだと考えましょう。
ロケール
ところで、曜日を表示するとどうなるでしょうか?%tA
を使って曜日を表示してみます。
jshell> "%tA".formatted(today) $6 ==> "日曜日"
日本語で「日曜日」と表示されました。もしかしたら「Sunday」と表示された人もいるかもしれません。これは、地域や言語によって表記を変える仕組みによるもので、このような仕組みを ロケール と言います。
言語の設定を変えて実行してみましょう。formatted
メソッドでは言語の設定を変更できないので、同じ動きをするString.format
メソッドを使ってみます。
例えば"%tA".formatted(today)
をString.format
メソッドを使って書き換えると次のようになります。
jshell> String.format("%tA", today) $10 ==> "日曜日"
format
メソッドの最初の引数にロケールを渡すことができます。英語を設定するときにはLocale.ENGLISH
を指定します。
jshell> String.format(Locale.ENGLISH, "%tA", today) $9 ==> "Sunday"
「Sunday」と表示されました。
日本語を指定する場合にはLocale.JAPANESE
を指定します。
jshell> String.format(Locale.JAPANESE, "%tA", today) $8 ==> "日曜日"
このように、ロケールとして言語を設定すると、それに従って表示がかわります。
練習
1. Locale.CHINESE
を指定して曜日を表示してみましょう。
タイムゾーン付日付時刻
「Java 17のリリースは14時30分だった」という話を聞いたとき、ちょっとおかしいと思いませんでしたか?Javaは世界中で使われています。どの地域でいう14時30分だったかは気になるところです。
日付時刻を使ってある瞬間を表すには、それがどの地域での日付時刻かを表す タイムゾーン の指定も必要になります。タイムゾーン付きの日付時刻としてZonedDateTime
クラスが用意されています。
ZonedDateTime.now()
として現在時刻を得てみましょう。
jshell> ZonedDateTime.now() $136 ==> 2021-09-19T06:05:21.549662100+09:00[Asia/Tokyo]
LocalDateTime
の場合と比べてみましょう。
jshell> LocalDateTime.now() $137 ==> 2021-09-19T06:06:38.967300300
ZonedDateTime
の値には現在時刻のあとに時差を表す「+09:00」とタイムゾーンを表す「Asia/Tokyo」がついていることがわかります。
UTC(協定世界時) は世界の時間の基準になる時間です。世界の時間はUTCからの時差をつかって表現されます。日本ではUTCから9時間の差があるので「+09:00」が表示されていました。
日本人が多く訪問している国・地域のタイムゾーンには次のようなものがあります。
ZoneId | 国・地域 |
---|---|
Asia/Tokyo | 日本 |
Asia/Seoul | 韓国 |
Asia/Shanghai | 中国 |
Asia/Taipei | 台湾 |
Asia/Bangkok | タイ |
Asia/Singapore | シンガポール |
Asia/Ho_Chi_Minh | ベトナム |
Asia/Manila | フィリピン |
US/Pacific | アメリカ西海岸 |
US/Eastern | アメリカ東海岸 |
Europe/Berlin | ドイツ |
Etc/UTC | 協定世界時 |
それでは、タイムゾーンを指定して今の時刻を得てみましょう。アメリカ東海岸でのいまの時刻を見てみます。アメリカ東海岸のタイムゾーンは「US/Eastern」で表します。
jshell> ZonedDateTime.now(ZoneId.of("US/Eastern")) $130 ==> 2021-09-18T13:07:29.331452500-04:00[US/Eastern]
アメリカ東海岸なのでニューヨークあたりの現在時刻がわかりました。
タイムゾーンはZoneId
クラスの値として指定します。ZoneId
の値を得るにはZonedId.of
メソッドにタイムゾーンを指定して呼び出します。
それではJava 17リリース日時をタイムゾーン付きで表してみましょう。Java 17はUTCでいう14時30分にリリースされました。そこでタイムゾーンにUTCを指定してみましょう。 「Etc/UTC」として指定します。
jshell> var java17 = ZonedDateTime.of(java17dateTime, ZoneId.of("Etc/UTC")) java17 ==> 2021-09-14T14:30Z[Etc/UTC]
これを日本時間で表してみましょう。 withZoneSameInstant
メソッドで、同じ瞬間の別のタイムゾーンでの時刻を表すことができます。
jshell> java17.withZoneSameInstant(ZoneId.of("Asia/Tokyo")) $94 ==> 2021-09-14T23:30+09:00[Asia/Tokyo]
つまり、Java 17は日本時間では夜の23時半にリリースされたわけですね。
コンピュータのタイムゾーンの設定を日本時間にしている人も多いと思います。 ZoneId.systemDefault
メソッドで動かしてるコンピュータのタイムゾーンを得ることができます。
jshell> java17.withZoneSameInstant(ZoneId.systemDefault()) $92 ==> 2021-09-14T23:30+09:00[Asia/Tokyo]
タイムゾーン付きの日付時刻は、夏の間に1時間早くなる夏時間などを考えると、日付と時刻には密接な関係があるためZonedDateTimeだけが用意されていて、日付だけをあらわすZonedDate
や時刻だけを表すZonedTime
はありません。
プログラムの勉強をしていると、日付時刻の表し方についても詳しくなっていきますね。
練習
1. いまの時刻がアメリカ西海岸では何時になっているか確認してみましょう。
2. 日本時間での2021年7月23日20時00分がシンガポールで何時だったか確認してみましょう。