[Java] Java1.8で追加されたDate and Time APIを使用してランダムな日付を生成する。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回はJava1.7以下でも使用できる方法を書きましたが、今回はJava1.8で追加されたDate and Time APIを使用して日付を生成する方法を調べたので書いておきます。

環境

Mac OSX 10.10.5 Yosemite
Java 1.8.0_91
Eclipse Mars2

Date and Time APIについて

Java1.7以前の問題を改善したもので、下記が大まかな特徴です。
スレッドセーフになった。
月を数値で指定する際に1始まりになり直感的なった。
日付/時間ライブラリのJoda-Time開発者との共同プロジェクト。

目的

指定した日から現在日を期間としてランダムな年月日を指定回数生成し、リストで返すメソッドを作成。

コード

	/**
	 * 指定した日から現在日を期間としてランダムな年月日を生成してリストで返す。
	 * countで生成する回数を指定する。
	 * Java 1.8以降が対象。
	 * @param year 年
	 * @param month 月
	 * @param day 日
	 * @param count 生成回数
	 * @return list ランダムな年月日のリスト
	 */
	private static List<String> createDateList8(int year, int month, int day, int count) {
		List<String> list = new ArrayList<>();
		
		for (int i = 0; i < count; i++) {
			long dayStart = LocalDate.of(year, month, day).getLong(ChronoField.EPOCH_DAY);
			long dayEnd   = LocalDate.now().getLong(ChronoField.EPOCH_DAY);

			LocalDate dateRandom;
			long dayPeriod;
			if (dayStart <= dayEnd) {
				dayPeriod = dayEnd - dayStart;
				dateRandom = LocalDate.now().minusDays(new Random().nextInt((int) dayPeriod));
			} else {
				dayPeriod = dayStart - dayEnd;
				dateRandom = LocalDate.now().plusDays(new Random().nextInt((int) dayPeriod));
			}
			
			if (i == count -1) {
				System.out.println("指定年月日の日数 : " + dayStart);
				System.out.println("現在年月日の日数 : " + dayEnd);	
				System.out.println("期間日数     : " + dayPeriod);
				System.out.println("作成年月日    : " + dateRandom);
			}
			
			list.add(dateRandom.toString());
		}
		
		return list;
	}
		
	public static void main(String[] args) {
		createDateList8(1997, 1, 1, 100);
	}

指定年月日(15行目)
LocalDate.of()で年月日を設定し、getLong(ChronoField.EPOCH_DAY)で日数を取得。
※EPOCH_DAY : Javaエポック1970-01-01 (ISO)を基準とするエポック日。

現在年月日(16行目)
LocalDate.now()で現在年月日を取得し、同様に日数を取得。

期間日数(18〜26行目)
20行目で指定年月日が過去か未来かで分岐し、期間日数を作成。
Random().nextInt()の引数に期間日数与えて乱数を作成し、
now().minusDays()及びnow().plusDays()で、現在年月日に乱数で増減させて年月日を作成。

確認(28〜33行目)

リストに追加(35行目)

リストを返す(38行目)

mainメソッド(41〜43行目)
上記メソッドを、年月日と作成回数を指定して呼び出しています。

実行結果

指定年月日の日数 : 9862
現在年月日の日数 : 17049
期間日数     : 7187
作成年月日    : 2009-06-12

期間内の日付で年月日が作成されています。

時間も取得したい場合

こんな風にできます。(秒の小数点以下は省略可能)

LocalDateTime ldt1 = LocalDateTime.of(2016, 9, 5, 0, 0, 0, 0);
LocalDateTime ldt2 = LocalDateTime.parse("2016-09-01T00:00:00.000");
System.out.println("LocalDateTime1 : " + ldt1);
System.out.println("LocalDateTime2 : " + ldt2);

実行結果

LocalDateTime1 : 2016-09-05T00:00
LocalDateTime2 : 2016-09-01T00:00

取得形式を指定したい場合

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println("DateTimeFormatter : " + dtf.format(ldt2));

実行結果

DateTimeFormatter : 2016/09/01

SimpleDateFormatと違ってスレッドセーフです。

その他

15行目でも使った様に、ChronoField.〜で様々な値を簡単に取得できます。
詳細については下記をご覧下さい。
列挙型ChronoField

さいごに

冒頭でも書いた通り、Java1.8で使用できるAPIなので、使用する場合はプロジェクトで使用できるか確認しておく必要が有ります。