- Java8のLocalDateとLocalDateTimeを変換してみた
- LocalDateTimeからLocalDateに変換する
- LocalDateの加算減算
- LocalDateとLocalDateを比較する
- 日付フォーマットする
- parseメソッドを使用して日付フォーマットする
- DateTimeFormatterのhhとHHの違い
- LocalDateとLocalDateの比較
- Periodクラス
- Durationクラス
- LocalDateをLocalDateTimeの00:00を求めるatStartOfDayメソッド
- OffsetDateTimeクラス
- タイムゾーン付きの文字列の日付をLocalDateTimeに変換する
- 文字列の日付妥当性チェック
- LocalDateTimeをjava.util.Dateに変換
- 日付の過去未来の複数条件の判定
- 関連
Java8のLocalDateとLocalDateTimeを変換してみた
Java8からLocalDateクラスというのが追加されていて色々調べてみました。
LocalDate date = new LocalDate(2019,1,1); // コンストラクタがprivateなのでNG LocalDate date = LocalDate.of(2019,2,28); // staticメソッドのofを使用してインスタンス生成する LocalDate date = LocalDate.of(2019,Month.APRIL,1); // Monthも使える
インスタンス生成方法はLocalDate.ofを使って生成します。 デフォルトはyyyy-MM-dd形式になります。ofメソッドでleap year(うるう年)の判定もしてくれるのでnew LocalDate(2019,2,29);なんてするとエラーが発生します。 今の時間でLocalDateを生成するにはnow()メソッドを使用します。
LocalDate date = LocalDate.now();// 2019-03-23
LocalDateもLocalDateTimeもタイムゾーンがないのでOSの日時を変更するとその時刻が表示されます。
LocalDateTimeからLocalDateに変換する
LocalDateTime dateTime = LocalDateTime.now(); LocalDate date = LocalDate.of(dateTime.getYear(), dateTime.getMonth(), dateTime.getDayOfMonth());
2022/05/15追記 java.time.temporal.TemporalAccessorインタフェースを使用して、LocalDateTimeからLocalDateに変換することができるようです。
TemporalAccessor temporalAccessor = LocalDateTime.now(); LocalDate date = LocalDate.from(temporalAccessor);
LocalDateの加算減算
LocalDateに日数を加算したい減算したいというケースが出てくると思います。 その場合はplusDays(int)やminusDays(int)で加減算することができます。基本的に用意されているメソッドは同じです。LocalDateTimeは時分秒を加減算するメソッドがあります。
LocalDate date = LocalDate.now(); date = date.plusDays(2); // 2日加算する System.out.println(date);
LocalDateとLocalDateを比較する
「2000年1月1日より未来日のデータを取得する」みたいな感じでLocalDate同士を比較するときがあると思います。 その場合はisAfterやisBeforeメソッドを使用します。
LocalDate today = LocalDate.now(); LocalDate tomorrow = LocalDate.now().plusDays(1); today.isAfter(today); // == falseとなるので注意(同一日はfalseとなる) today.isAfter(tomorrow); // == false tomorrow.isAfter(today); // == true today.isBefore(today); // == falseとなるので注意(同一日はfalseとなる) today.isBefore(tomorrow); // == true tomorrow.isBefore(today); // == false
isAfterやisBeforeメソッドは同一日を含まないので、「2000年1月1日含む未来日のデータを取得する」という場合はequalsメソッドを併用しないと期待した動きとなりません。
LocalDate today = LocalDate.of(2000,1,1); LocalDate date = LocalDate.of(2000,1,1); today.isBefore(date) || today.equals(date); // == true
日付フォーマットする
LocalDateもLocalDateTimeも日付フォーマットするには、DateTimeFormatterクラスを使用します。戻り値はString型になります。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date = LocalDate.of(2019,3,23);
System.out.println(date.format(formatter)); // 2019/03/23
parseメソッドを使用して日付フォーマットする
formatメソッドだとString型に変換されてしますので、LocalDate.parseメソッドを使用して日付フォーマットします。この場合は戻り値はLocalDate型になります。
LocalDate.parse("2019/02/29",DateTimeFormatter.ofPattern("yyyy/MM/dd")); // 2019/02/28となってインスタンス生成される
良きに計らってくれるようですが、第一引数が文字列で動的に来ると考えると、エラーとしたい場合があると思います。 その場合はyyyyをuuuuに変更してwithResolverStyle(ResolverStyle.STRICT)メソッドを指定します。
LocalDate.parse("2019/11/31",
DateTimeFormatter
.ofPattern("uuuu/MM/dd")
.withResolverStyle(ResolverStyle.STRICT)); // java.time.DateTimeException: Invalid date 'NOVEMBER 31'
DateTimeFormatterのhhとHHの違い
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss");
LocalDateTime dateTime = LocalDateTime.of(LocalDate.of(2019, 3, 23), LocalTime.of(23, 50, 1, 1));
System.out.println(dateTime.format(formatter)); // 2019/03/23 11:50:01となってしまう
23と指定するとエラーとならずに11になってしまいます。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.of(LocalDate.of(2019, 3, 23), LocalTime.of(23, 50, 1, 1));
System.out.println(dateTime.format(formatter)); // 2019/03/23 23:50:01と意図したとおり表示される
HHで指定すると23は23として表示されます。 ちなみにこれをLocalDateTime.parseメソッドで行うとエラーとなります。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse("2019/03/23 23:50:01",formatter);
System.out.println(dateTime.format(formatter)); // DateTimeParseException: Text '2019/03/23 23:50:01' could not be parsed: Invalid value for ClockHourOfAmPm (valid values 1 - 12): 23
LocalDateとLocalDateの比較
LocalDateとLocalDateの比較にはequalsメソッドを使用します。(isEqualメソッドでも可能)
LocalDate ld1 = LocalDate.of(2010, 1, 1);
LocalDate ld2 = LocalDate.parse("2010-01-01");
System.out.println(ld1.equals(ld2)); // trueと表示されます
LocalDate ld3 = LocalDate.parse("2019/01/01",DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(ld1.isEqual(ld3)); // falseと表示されます
Periodクラス
日にちを扱っているとjava.time.Periodクラスも出てくると思います。 Periodクラスは日にちの量を表すクラスで、betweenメソッドやofメソッドでインスタンス生成します。以下、betweenメソッドを使用しています。
LocalDate ld1 = LocalDate.of(2010, 1, 1);
LocalDate ld2 = LocalDate.parse("2019/02/03",DateTimeFormatter.ofPattern("yyyy/MM/dd"));
Period period = Period.between(ld1, ld2);
System.out.println(period); // P9Y1M2D 9年1ヶ月2日の差がある
System.out.println(period.getYears()); // 9
System.out.println(period.getMonths()); // 1
System.out.println(period.getDays()); // 2
System.out.println(period.toTotalMonths()); // 109
toTotalMonthsメソッドは9年1ヶ月=109ヶ月を返します。その他はメソッド名通りです。 以下、ofメソッドを使用しています。
Period period = Period.of(10, 9, 8); System.out.println(period); // P10Y9M8D 10年9ヶ月8日の差がある System.out.println(period.getYears()); // 10 System.out.println(period.getMonths()); // 9 System.out.println(period.getDays()); // 8 System.out.println(period.toTotalMonths()); // 129
Durationクラス
Periodクラスに対してDurationクラスは時間の量を表すクラスです。 以下、betweenメソッドを使用しています。
LocalDateTime ld1 = LocalDateTime.of(2010, 1, 1, 0, 0);
LocalDateTime ld2 = LocalDateTime.parse("2010/01/02 112040",DateTimeFormatter.ofPattern("yyyy/MM/dd HHmmss"));
Duration duration = Duration.between(ld1, ld2);
System.out.println(duration); //PT35H20M40S -> 35時間20分40秒の差がある
System.out.println(duration.toDays()); // 1日
System.out.println(duration.toHours()); // 35時間
System.out.println(duration.toMinutes()); // 2120分
System.out.println(duration.getSeconds()); // 127240秒
LocalDateをLocalDateTimeの00:00を求めるatStartOfDayメソッド
LocalDateからLocalDateTimeに変換する方法として、00:00にするのならatStartOfDayメソッドを使用することでその日にちの00:00のLocalDateTimeに変換することができます。
LocalDate ld = LocalDate.of(2019, Month.APRIL, 1); System.out.println((ld.atStartOfDay())); // 2019-04-01T00:00
OffsetDateTimeクラス
OffsetDateTimeクラスは時差ありの日付を表すクラスです。 2020-09-15T19:16:39.265866700+09:00というようにJSTの場合+09:00がついたり、UTCの場合は2020-09-15T10:16:39.265866700Zというように末尾にZが付きます。 また、LocalDateTimeのインスタンスをOffsetDateTimeクラスのインスタンスに変換することも可能です。
package jp.co.offsetdatetimes;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class OffsetDateTimeSample {
public static void main(String[] args) {
// JST表示
OffsetDateTime odtjst = OffsetDateTime.now(ZoneId.of("Asia/Tokyo")); // JST
System.out.println(odtjst); // 2020-09-15T19:16:39.265866700+09:00
// JSTをUTCに変換
OffsetDateTime odtutc = OffsetDateTime.ofInstant(odtjst.toInstant(), ZoneId.of("UTC")); // UTC
System.out.println(odtutc); // 2020-09-15T10:16:39.265866700Z
// LocalDateTimeをOffsetDateTimeに変換
LocalDateTime ldt = LocalDateTime.now();
ZoneOffset offset = ZoneId.of("UTC").getRules().getOffset(odtjst.toInstant());
OffsetDateTime odt = OffsetDateTime.of(ldt, offset);
System.out.println(odt); // 2020-09-15T19:16:39.265866700Z
}
}
タイムゾーン付きの文字列の日付をLocalDateTimeに変換する
タイムゾーン付きの文字列の日付をLocalDateTimeに変換する例です。 ZonedDateTime,ZoneIdクラスを使用します。
package jp.co.confrage;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
public class DateTest {
public static void main(String[] args) throws InterruptedException {
String inputValue = "20201230T000000+0800";
ZonedDateTime value =
ZonedDateTime.parse(
inputValue,
DateTimeFormatter.ofPattern("uuuuMMdd'T'HHmmssZ")
.withChronology(IsoChronology.INSTANCE)
.withResolverStyle(ResolverStyle.STRICT));
ZonedDateTime jst = value.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println(jst); // 2020-12-30T01:00+09:00[Asia/Tokyo]
var dt = jst.toLocalDateTime();
System.out.println(dt); // 2020-12-30T01:00
}
}
一旦UTCに変換すれば時間はわかりやすいと思います。 |JST|UTC|結果| |:–|:–|:–| |2020/12/30 09:00:00+0900|2020/12/30 00:00:00Z|違う時間| |2020/12/30 10:00:00+0900|2020/12/30 01:00:00Z|同じ時間| |2020/12/30 09:00:00+0800|2020/12/30 01:00:00Z|同じ時間| UTCに変換すれば同じ時間であることがわかります。
文字列の日付妥当性チェック
文字列の日付が厳密に妥当かどうかをparseメソッドでチェックするメソッドです。
private boolean validateLocalDateTime(final String inputDateValue) { // "20200229T124440+0900"
try {
final LocalDateTime value =
LocalDateTime.parse(
inputDateValue,
DateTimeFormatter.ofPattern("uuuuMMdd'T'HHmmssZ")
.withChronology(IsoChronology.INSTANCE)
.withResolverStyle(ResolverStyle.STRICT));
return true;
} catch (final DateTimeParseException e) {
e.printStackTrace();
return false;
}
}
LocalDateTimeをjava.util.Dateに変換
あまりこの変換をするケースはないと思いますが、以下のようにtoDateメソッドを使用して変換することが出来ます。
LocalDateTime ldt = LocalDateTime.now(); ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault()); Date dt = Date.from(zdt.toInstant()); // Fri Oct 30 11:30:15 GMT+09:00 2020
※java.util.Dateはほとんど非推奨です
日付の過去未来の複数条件の判定
複数条件の日付判定を書くときは、isAfterやisBeforeを使います。 「父の誕生日>母の誕生日>兄の誕生日>弟の誕生日」の整合性が取れている確認です。 streamとallMatchメソッドを使って書いています。
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Main {
public static void main(String[] args) {
final LocalDateTime dt1 = LocalDateTime.of(1970, 1, 1, 0, 0); // 父 一番過去日
final LocalDateTime dt2 = LocalDateTime.of(1975, 1, 1, 0, 0); // 母
final LocalDateTime dt3 = LocalDateTime.of(2000, 1, 1, 0, 0); // 兄
final LocalDateTime dt4 = LocalDateTime.of(2003, 1, 1, 0, 0); // 弟 一番未来日
final List<LocalDateTime> lists = new LinkedList<>();
lists.add(dt1);
lists.add(dt2);
lists.add(dt3);
lists.add(dt4);
if (lists.size() == 1) {
return;
}
// 父 < 母 < 兄 < 弟となっている事のチェック
final List<Boolean> checkResults = new ArrayList<>();
for (int i = 0; i < lists.size() - 1; i++) {
System.out.println(lists.get(i).isBefore(lists.get(i + 1)));
checkResults.add(lists.get(i).isBefore(lists.get(i + 1))); // true,true,true
}
final boolean result = checkResults.stream().allMatch(e -> e.equals(Boolean.TRUE));
System.out.println(result); // true
}
}

KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^


コメント
LocalDateTime から LocalDate に変換するのは、 LocalDate.from(TemporalAccessor) を使うのが手っ取り早いと思います。
LocalTime への変換も同様ですね。
知りませんでした!
ありがとうございます!^^