- 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 への変換も同様ですね。
知りませんでした!
ありがとうございます!^^