検索

キーワード


【Java】Java8からの現在や指定日時取得 9クラスの基本と使い方を解説

  • 公開日:2021-01-26 08:21:20
  • 最終更新日:2021-01-25 13:28:47
【Java】Java8からの現在や指定日時取得 9クラスの基本と使い方を解説

こんにちは、研修を終えたばかりの駆け出しエンジニアの伊藤です。


東京ITカレッジのJava研修で学んだ内容を復習も兼ねて記事にしたいと思います。


今回は、Java8から採用された新APIを使った日時取得方法について説明します。

この記事では、最低限覚えておいてほしいクラスとして、日付と時刻を表すクラスと基本的な使い方のみを紹介します。

日時加算減算やフォーマット、日時比較については別記事でご紹介しますので、関連記事を参考にしてください。

Javaやプログラムについて勉強し始めた方の参考になれば幸いです!

(eclipseを使用して計算を行っています)


関連記事:よく使う日時クラス解説まとめ

     日時取得の Date/Calendar クラスの基本と使い方を解説

     Date/Calendarの日時フォーマット/日時計算/日時比較クラス使い方解説

     Java8からの日時計算/日時比較クラスの使い方を解説

     Java8からの日時フォーマットクラスの使い方解説

     日付時刻の変換方法(新旧 API 相互変換、Data/Calendar の変換)

     処理時間(経過時間)計測に使える2つのメソッドを解説



日時取得(新API)


DateAndTimeAPI 概要

 Java8より導入された、日付と時刻に関する新しいAPIです。


 従来の日時管理を行っていた「java.util.Date」「 java.util.Calendar」とはベースから大幅に変更されているため、使い方が変わっているところが多々あります。


 今までの「java.util.Date」はJava言語の初期から存在し、その当時普及していた「UNIX時刻」というものをベースとして作られています。しかし、現在は「ISO8601(日付と時刻の表記に関するISOの国際規格)」が主流となっており、DateAndTimeAPIも時代の流れに合わせ、ISO8601をベースとして作られました。


 旧APIとの大きく違う点としては、以下のことが挙げられます。

・日付、時間、日時をそれぞれ別クラスとして扱っている。

(旧APIでは、日付、時間、日時、共に「java.util.Date」から一括して取得し、その中のどれをインスタンスして取るかを再度宣言していた)>

・データ保持と日付操作(年/月/日フィールドの取得/変更など)が1つのクラスで出来るようになった。

(旧APIでは、データ保持はDateクラス、日付操作はCalendarクラスと用途によってクラスの使い分けが必要だった)

・日時クラスは、Immutable(不変)なオブジェクトであるため、既存インスタンスの値を変更する際は新しくインスタンスが生成される。

(Javaはオブジェクト指向言語のため、参照としてメモリへアクセスしやり取りする。新APIは日時クラスにおいてimmutableを採用しているため、オブジェクトの複製はオブジェクト全体ではなく、参照の複製だけで済むため、メモリの節約、プログラム実行の高速化が実現できる。逆に旧APIでは、mutable(可変)なため、オブジェクトに変更を加えることが可能である。しかし、1つのオブジェクトを変更すると、参照しているところすべてが影響を受けてしまうため、バグが発生する可能性があった)

・スレッドセーフである。

(旧APIでは、スレッドセーフではないため、マルチスレッド(並列処理)で用いると、思っていたような結果が反映されず、分かりづらいバグとして出力されてしまうことがあった)

より、便利で安全に使うことができるように作られたのが新API(DateAndTimeAPI)になります。


関連記事:Java Date-Time Packages(DateAndTimeAPI)(Oracle)

 


 

現在日時を取得する方法

DateAndTimeAPIでの現在の日時取得方法は、大きく分けタイムゾーンのあり・なしがあります。

タイムゾーンとは、イギリスのグリニッジ天文台を基準に、標準時を同じ地域ごとに区切った時間帯のことを言います。

日本で言うと、韓国やインドネシア東部と同じタイムゾーンにあります。


・基本的な現在の日時取得方法(タイムゾーンなし)
  ・java.time.LocalDate(日付)
  ・java.time.LocalTime(時刻)
  ・java.time.LocalDateTime(日付と時刻)
  ・java.time.temporal.TemporalAdjusters(曜日や月、日、時間等)

・タイムゾーンを指定する場合の日時取得方法
  ・java.time.OffsetTime(時刻)
  ・java.time.OffsetDateTime(日時)
  ・java.time.ZoneOffset(タイムゾーンオフセット)
  ・java.time.ZonedDateTime(日付と時刻)
  ・java.time.ZoneId(タイムゾーン特定)




基本的な現在の日時取得方法(タイムゾーンなし)

現在の日時を取得するには、now()メソッドを使用します。


  ・日付のみ取得	
   LocalDate 変数名 = LocalDate.now();

  ・時刻のみ取得	
   LocalTime 変数名 = LocalTime.now();

  ・日付と時刻を取得	
   LocalDateTime 変数名 = LocalDateTime.now();

//日時取得(タイムゾーンなし)サンプル
import java.time.LocalDate;		
import java.time.LocalTime;		
import java.time.LocalDateTime;

public class LocalDateTimeTest {

	public static void main(String[] args) {

	    System.out.println("---取得結果--------------------");
		//日付のみ取得
		LocalDate localDate = LocalDate.now();
		System.out.println("日付のみ :" + localDate);
//時刻のみ取得 LocalTime localTime= LocalTime.now(); System.out.println("時刻のみ :" + localTime);
//日付と時刻を取得 LocalDateTime localDateTime = LocalDateTime.now(); System.out.println("日時と時刻:" + localDateTime);
} }


---取得結果--------------------
日付のみ :2020-07-22
時刻のみ :13:49:14.484678100
日時と時刻:2020-07-22T13:49:14.484678100


DateAndTimeAPIでは、

①表示形式の指定は必要ない(DateAndTimeAPIの基本表示が「YYYY-MM-DD」形式となっているため)

②コンストラクタは用意されていないため、newすることができない

上記が「java.util.Date」とのプログラム上での主な変更点です。

旧APIにおいては、日付を取得する際「Java.util.Date」を使っていたが、日付以外の物(時間等)も一緒に取得するしかなく、ソースを見ただけでは何を取得したのかが分かりにくかったです。しかし、新APIからは明示的に日付を表す「LocalDate」メソッドがあることで、何を取得したのかが分かりやすくなりました。


取得結果の小数点以下時間は、ナノ秒です。(旧APIにおいては、ミリ秒までしか表示できませんでした)






日付、時刻を指定しての取得方法(タイムゾーンなし)

特定の日時を指定するには、ofメソッドを使用します。


    ・日付のみ指定	
   LocalDate 変数名 = LocalDate.of(,,);

  ・時刻のみ取得	
   LocalTime 変数名 = LocalTime.of(,,);

  ・日付と時刻を取得	
   LocalDateTime 変数名 = LocalDateTime.of(,,,,,);


//指定取得サンプル
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;

public class LocalDateTimeDesignationTest {

	public static void main(String[] args){

		System.out.println("---取得結果--------------------");
		//日付指定(2030年1月2日)
		LocalDate localDate = LocalDate.of(2030, 1, 2);
		System.out.println("日付指定  :" + localDate);
//時刻指定(20時52分08秒) LocalTime localTime = LocalTime.of(20, 52, 8); System.out.println("時刻のみ :" + localTime);
//日付と時刻(2030年01月02日20時52分18秒) LocalDateTime localDateTime = LocalDateTime.of(2030, 01, 02, 20, 52, 18); System.out.println("日付と時刻:" + localDateTime);
} }


---取得結果--------------------
日付のみ :2030-01-02
時刻のみ :20:52:08
日付と時刻:2030-01-02T20:52:08





色々な日時取得

java.time.temporal.TemporalAdjusters を使用すると、色々な日時の取得ができます。

下記サンプルでは、ofメソッドで指定した日付を元に月末日、次の水曜日を求めています。


//java.time.temporal.TemporalAdjustersを使用した日時の取得サンプル
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

public class LocalDateTemporalAdjustersTest {

	public static void main(String[] args) {

		System.out.println("---取得結果--------------------");
		// 指定日付(2030-02-02)
    	LocalDate localDate = LocalDate.of(2030, 2, 2);
    	System.out.println("日付指定 :" + localDate);
// 上記指定日付の月末日(2030-02-28) LocalDate localDateMonth = localDof.with(TemporalAdjusters.lastDayOfMonth()); System.out.println("月末指定 :" + localDateMonth);
// 上記指定日付から次の水曜日 LocalDate localDateWeek = localDweek.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY)); System.out.println("指定曜日 :" + localDateWeek);
} }


---取得結果--------------------
日付指定 :2030-02-02
月末指定 :2030-02-28
指定曜日 :2030-02-06


java.util.Calendar の時は、Month取得は 0 から始まりましたが、java.time.temporal.TemporalAdjusters においては、1 から始まるところが違っています。





タイムゾーンを加味した現在日時取得方法

UTC(協定世界時)を基本に時差の取得を行います。


    ・時刻+UTCとの時差取得	
   OffsetTime 変数名 = OffsetTime.now();

  ・日付と時刻+UTCとの時差取得
   OffsetDateTime 変数名 = OffsetDateTime.now();

  ・日付と時刻+UTCとの時差と地域取得	
   ZonedDateTime 変数名 = ZonedDateTime.now();


//タイムゾーンを加味した現在日時取得方法サンプル
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZonedDateTime;

public class OffsetDateTimeTest {

	public static void main(String[] args) {

		System.out.println("---取得結果--------------------");
		//時刻+UTCとの時差取得
		OffsetTime offsetTime = OffsetTime.now();
		System.out.println("1.日付のみ :" + offsetTime);
//日付と時刻+UTCとの時差取得 OffsetDateTime offsetDateTime = OffsetDateTime.now(); System.out.println("2.時間のみ :" + offsetDateTime);
//日付と時刻+UTCとの時差と地域取得 ZonedDateTime zonedDateTime = ZonedDateTime.now(); System.out.println("4.日付+時間:" + zonedDateTime);
} }

  

---取得結果--------------------
日付のみ :16:27:48.589175600+09:00
時間のみ :2020-07-17T16:27:48.591145300+09:00
日付+時間:2020-07-17T16:27:48.591145300+09:00[GMT+09:00]


 日付+時間の取得結果、前側の+9:00はUTCから取得した世界共通の標準時で一番最後、[GMT+9:00]のGMTは、グリニッジ標準時での表示です。(UTCはGMTを人工的に調整して、世界共通の標準時と定めたものです)

 UTCとGMTは国際協定では等しいとなっているため、Javaの取得においては同じ時間がインスタンスとして返されます。違いとしては、測定方法とわずかな秒数の差(現在は32秒)です。





タイムゾーンを意識した現在日時を取得する方法

タイムゾーンを意識した現在日時を取得する方法として、地域ベースID指定方法があります。

今回は引数に、ZonedId を指定することで実現しています。


    ・日付と時刻+UTCとの時差取得
   OffsetDateTime 変数名 = OffsetDateTime.now(ZoneId.of("地域名/地名/時差"));

  ・日付と時刻+UTCとの時差と地域取得	
   ZonedDateTime 変数名 = ZonedDateTime.now(ZonedId.of("地域名/地名/時差"));


//地域ベース指定サンプル
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class ZonedDateTimeTest {

	public static void main(String[] args) {

		System.out.println("---取得結果--------------------");
		//日付・時刻+UTCとの時差を取得
		OffsetDateTime offsetParis = OffsetDateTime.now(ZoneId.of("CET"));
		System.out.println("offset(パリ):" + offsetParis);
OffsetDateTime offsetJapan = OffsetDateTime.now(ZoneId.of("Asia/Tokyo")); System.out.println("offset(日本): " + offsetJapan);
//日付・時刻+UTCとの時差とタイムゾーン ZonedDateTime zonedParis = ZonedDateTime.now(ZoneId.of("CET")); System.out.println("zoned(パリ) : " + zonedParis);
ZonedDateTime zonedJapan = ZonedDateTime.now(ZoneId.of("Asia/Tokyo")); System.out.println("zoned(日本) : " + zonedJapan);
// System.out.println("---オフセットタイムゾーン範囲結果------"); //オフセットタイムゾーン範囲 ZoneOffset zoneOffsetMax = ZoneOffset.MAX; System.out.println("MAX:" + zoneOffsetMax);
ZoneOffset zoneOffsetMin = ZoneOffset.MIN; System.out.println("MIN:" + zoneOffsetMin);
ZoneOffset zoneOffsetUtc = ZoneOffset.UTC; System.out.println("UTC:" + zoneOffsetUtc);
} }


---取得結果--------------------
offset(パリ): 2020-07-20T11:40:25.431367100+02:00
offset(日本): 2020-07-20T18:40:25.432364400+09:00
zoned(パリ) : 2020-07-20T11:40:25.433361600+02:00[CET]
zoned(日本) : 2020-07-20T18:40:25.433361600+09:00[Asia/Tokyo]
---オフセットタイムゾーン範囲結果------
MAX:+18:00
MIN:-18:00
UTC:Z


地域ベースIDは、タイムゾーン(共通の標準時を使う地域全体)ごとに設定された地域名(ID)等からUTCとの差を割り出すものです。



OffsetDateTime と ZonedDateTime の違い

 OffsetDateTime:時差のみを取得するため、サマータイム等の各地域の時間に変化がある場合も、システムに変化は起こらない。

 ZonedDateTime :時差に加えて地域を取得するため、サマータイム等の各地域の時間に変化がある場合、システムに変化が起こる。



オフセットタイムゾーン範囲とは、タイムゾーンがグリニッジ/UTCと異なる期間を表すため用意された最大値と最小値範囲です。

タイムゾーンの基準点からの距離の位置(オフセット)は世界の地域ごとに異なります(サマータイム導入等)。

上記サンプルを例に、パリ(中央ヨーロッパ時間‐CET)は、冬はグリニッジ/UTCから1時間進み、夏にはサマータイム導入のため、2時間進みます。パリのZoneIdインスタンスは2つのZoneOffsetインスタンス(冬は+01:00インスタンス、夏は+02:00インスタンス)を参照します。

世界中のサマータイム等に対応するため、オフセットの範囲は-18:00から+18:00までに制限されています。そのため、オフセットタイムゾーン範囲結果として最大値が+18時間、最小値が‐18時間が返っています。

また、UTC0は世界標準時の基準となるため、結果として「Zero Time」の「Z」が返ります。



文字列から日時を作成する方法

ISO日時フォーマットを使うと、文字列から日時を作成することができます。

ここでは、parseメソッド(日時文字列から生成)を使用します。


//文字列から日時を作成サンプル
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;

public class ParseTest {

	public static void main(String[] args) {

		System.out.println("---取得結果(タイムゾーンなし)--------------------");
		//引数で指定した文字列から日時インスタンスを作成する
		LocalDate localDate = LocalDate.parse("2020-08-05");
		System.out.println("日付のみ:" + localDate);
LocalDateTime localDateTime = LocalDateTime.parse("2021-08-05T11:50:55"); System.out.println("日時のみ:" + localDateTime);
System.out.println("---取得結果(タイムゾーンあり)--------------------"); ZonedDateTime zonedDateTime = ZonedDateTime.parse("2022-08-05T10:15:30+09:00[Asia/Tokyo]"); System.out.println("タイムゾーン:" + zonedDateTime);
} }


---取得結果(タイムゾーンなし)--------------------
日付のみ:2020-08-05
日時のみ:2021-08-05T11:50:55
---取得結果(タイムゾーンあり)--------------------
タイムゾーン:2022-08-05T10:15:30+09:00[Asia/Tokyo]





Java8から採用された新API(DateAndTimeAPI)での現在日時や指定した日時取得方法は分かったでしょうか?

今回は基本的な一部しかご紹介できませんでしたが、まだ色々なAPIが用意されています。調べてみると楽しい発見があるかと思います!

また、従来APIの日時取得方法と比べてみると理解度が上がると思いますので、ぜひ読んでみてください。


関連記事:よく使う日時クラス解説まとめ

     日時取得の Date/Calendar クラスの基本と使い方を解説

     Date/Calendarの日時フォーマット/日時計算/日時比較クラス使い方解説

     Java8からの日時計算/日時比較クラスの使い方を解説

     Java8からの日時フォーマットクラスの使い方解説

     日付時刻の変換方法(新旧 API 相互変換、Data/Calendar の変換)

     処理時間(経過時間)計測に使える2つのメソッドを解説


【著者】

伊藤

Javaを研修で3か月学んだ、駆け出しのエンジニアです。
現在は、ベンダー資格を取得するため、勉強を日課にできるよう努力中です。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様