Java8のバージョンから、日付関連の処理はLocalDateTime型が利用できるようになった。そのため、開発現場でもLocalDateTime型を利用するように求められてきている。また、日付チェック処理は、SimpleDateFormatでなく、DateTimeFormatterを利用する必要がある。
日付関連の処理としてよく使うものに、日付の妥当性チェックや、日付型⇔文字列型の変換処理がある。これらの実装方法は自力で作ると不具合が起こりやすい。そこで、どのような実装を行えばよいか、その内容をサンプルプログラムとしてまとめることで防備録として残したかったため、その内容を共有する。
前提条件
下記記事のIntelliJ IDEA Community版をダウンロード済であること。
また、下記のように、「demoJava」というJavaプロジェクトを作成済であること。
なお、IntelliJ IDEA上でJavaプロジェクトを作成する方法については、IntelliJ IDEA Community版をダウンロードする記事内の、「IntelliJ IDEA上でのJavaプロジェクトの作成・実行」を参照のこと。
やってみたこと
サンプルプログラムの構成と共通処理
また、今回共通で利用する「StringCheckUtil.java」は以下の通りで、文字列のnull・空文字チェックを行っている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class StringCheckUtil { /** * 引数の文字列がnull、空文字かどうかを判定する * @param str チェック対象文字列 * @return 文字列チェック結果 */ public static boolean isEmpty(String str){ if(str == null || "".equals(str)){ return true; } return false; } } |
日付チェック処理の実装と結果検証
日付チェック処理の確認は、「CheckDate.java」で行った。Java8以降とそれ以前で、日付チェック処理の実装が大きく異なるので注意が必要である。また、Java8以降で使用するDateTimeFormatterでは、暦体系に和暦体系を指定したり、ResolverStyleにSTRICT(厳密)の指定したりすることが必要な点も注意が必要である。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.ResolverStyle; public class CheckDate { public static void main(String[] args){ System.out.println("*** Java8で確認した結果 ***"); System.out.println("uuuuが西暦の年として判定される"); System.out.println("2019年2月29日は存在しないので、falseとして判定される"); System.out.println("20191019_yyyyMMdd : " + isCorrectDateByJava8("20191019", "yyyyMMdd")); System.out.println("20190229_yyyyMMdd : " + isCorrectDateByJava8("20190229", "yyyyMMdd")); System.out.println("20191019_uuuuMMdd : " + isCorrectDateByJava8("20191019", "uuuuMMdd")); System.out.println("20190229_uuuuMMdd : " + isCorrectDateByJava8("20190229", "uuuuMMdd")); System.out.println(); System.out.println("*** Java7で確認した結果 ***"); System.out.println("yyyyが西暦の年として判定される"); System.out.println("2019年2月29日は存在しないので、falseとして判定される"); System.out.println("20191019_yyyyMMdd : " + isCorrectDateByJava7("20191019", "yyyyMMdd")); System.out.println("20190229_yyyyMMdd : " + isCorrectDateByJava7("20190229", "yyyyMMdd")); System.out.println("20191019_uuuuMMdd : " + isCorrectDateByJava7("20191019", "uuuuMMdd")); System.out.println("20190229_uuuuMMdd : " + isCorrectDateByJava7("20190229", "uuuuMMdd")); } /** * Java8以降で利用できるDateTimeFormatterを利用して日付チェックを行う * @param dateStr チェック対象文字列 * @param dateFormat 日付フォーマット * @return 日付チェック結果 */ private static boolean isCorrectDateByJava8(String dateStr, String dateFormat){ if(StringCheckUtil.isEmpty(dateStr) || StringCheckUtil.isEmpty(dateFormat)){ return false; } //暦体系は和暦体系で、日付と時刻を厳密に解決するスタイルで、 //DateTimeFormatterオブジェクトを作成 DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat) .withChronology(JapaneseChronology.INSTANCE) .withResolverStyle(ResolverStyle.STRICT); try{ //チェック対象文字列をLocalDate型の日付に変換できれば、チェックOKとする LocalDate.parse(dateStr, df); return true; }catch(Exception e){ return false; } } /** * Java7以前で利用していたSimpleDateFormatを利用して日付チェックを行う * @param dateStr チェック対象文字列 * @param dateFormat 日付フォーマット * @return 日付チェック結果 */ private static boolean isCorrectDateByJava7(String dateStr, String dateFormat){ if(StringCheckUtil.isEmpty(dateStr) || StringCheckUtil.isEmpty(dateFormat)){ return false; } //SimpleDateFormatオブジェクトを作成 SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); //日付と時刻を厳密に解決するスタイルを指定 sdf.setLenient(false); try{ //チェック対象文字列をDate型の日付に変換できれば、チェックOKとする sdf.parse(dateStr); return true; }catch(Exception e){ return false; } } } |
日付型を文字列型に変換する処理の実装と結果検証
日付型を文字列型に変換する処理の確認は、「ConvertDateToStr.java」で行った。今回はJava8以降で利用できるDateTimeFormatterを利用している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import java.time.LocalDate; import java.time.chrono.JapaneseDate; import java.time.format.DateTimeFormatter; import java.time.format.ResolverStyle; public class ConvertDateToStr { public static void main(String[] args){ //1年前の日付 JapaneseDate jd1 = JapaneseDate.of(2018, 10, 19); LocalDate ld1 = LocalDate.of(2018, 10, 19); System.out.println("*** 1年前の日付(本日日付:2019年10月19日) ***"); System.out.println("和暦 : " + convertJapaneseDateToStr(jd1, "Gyy年MM月dd日")); System.out.println("西暦 : " + convertLocalDateToStr(ld1, "uuuu年MM月dd日")); System.out.println(); //本日の日付 JapaneseDate jd2 = JapaneseDate.now(); LocalDate ld2 = LocalDate.now(); System.out.println("*** 本日の日付(本日日付:2019年10月19日) ***"); System.out.println("和暦 : " + convertJapaneseDateToStr(jd2, "Gyy年MM月dd日")); System.out.println("西暦 : " + convertLocalDateToStr(ld2, "uuuu年MM月dd日")); System.out.println(); //1年後の日付 JapaneseDate jd3 = JapaneseDate.from(LocalDate.of(2020, 10, 19)); LocalDate ld3 = LocalDate.from(jd3); System.out.println("*** 1年後の日付(本日日付:2019年10月19日) ***"); System.out.println("和暦 : " + convertJapaneseDateToStr(jd3, "Gyy年MM月dd日")); System.out.println("西暦 : " + convertLocalDateToStr(ld3, "uuuu年MM月dd日")); } /** * 日付(西暦)を文字列変換した結果を返す * @param localDate 日付(西暦) * @param dateFormat 日付(西暦)のフォーマット * @return 変換後の文字列 */ private static String convertLocalDateToStr(LocalDate localDate , String dateFormat){ if(localDate == null || StringCheckUtil.isEmpty(dateFormat)){ return null; } //暦体系は和暦体系で、日付と時刻を厳密に解決するスタイルで、 //DateTimeFormatterオブジェクトを作成 DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat) .withChronology(JapaneseChronology.INSTANCE) .withResolverStyle(ResolverStyle.STRICT); //引数の日付(西暦)を文字列に変換して返す return localDate.format(df); } /** * 日付(和暦)を文字列変換した結果を返す * @param japaneseDate 日付(和暦) * @param dateFormat 日付(和暦)のフォーマット * @return 変換後の文字列 */ private static String convertJapaneseDateToStr(JapaneseDate japaneseDate , String dateFormat){ if(japaneseDate == null || StringCheckUtil.isEmpty(dateFormat)){ return null; } //暦体系は和暦体系で、日付と時刻を厳密に解決するスタイルで、 //DateTimeFormatterオブジェクトを作成 DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat) .withChronology(JapaneseChronology.INSTANCE) .withResolverStyle(ResolverStyle.STRICT); //引数の日付(和暦)を文字列に変換して返す return japaneseDate.format(df); } } |
文字列型を日付型に変換する処理の実装と結果検証
文字列型を日付型に変換する処理の確認は、「ConvertStrToDate.java」で行った。今回はJava8以降で利用できるDateTimeFormatterを利用している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import java.time.LocalDate; import java.time.chrono.JapaneseChronology; import java.time.chrono.JapaneseDate; import java.time.format.DateTimeFormatter; import java.time.format.ResolverStyle; import java.util.Locale; public class ConvertStrToDate { public static void main(String[] args){ //1年前の日付 System.out.println("*** 1年前の日付(本日日付:2019年10月19日) ***"); System.out.println("'20181019'⇒LocalDate : " + convertStrToLocalDate("20181019", "uuuuMMdd")); System.out.println("'平成30年10月19日'⇒LocalDate : " + convertStrToLocalDate("平成30年10月19日", "GGGGy年MM月dd日")); System.out.println("'20181019'⇒JapaneseDate : " + JapaneseDate.from(convertStrToLocalDate("20181019", "uuuuMMdd"))); System.out.println(); //本日の日付 System.out.println("*** 本日の日付(本日日付:2019年10月19日) ***"); System.out.println("'20191019'⇒LocalDate : " + convertStrToLocalDate("20191019", "uuuuMMdd")); System.out.println("'令和1年10月19日'⇒LocalDate : " + convertStrToLocalDate("令和1年10月19日", "GGGGy年MM月dd日")); System.out.println("'20191019'⇒JapaneseDate : " + JapaneseDate.from(convertStrToLocalDate("20191019", "uuuuMMdd"))); System.out.println(); //1年後の日付 System.out.println("*** 1年後の日付(本日日付:2019年10月19日) ***"); System.out.println("'20201019'⇒LocalDate : " + convertStrToLocalDate("20201019", "uuuuMMdd")); System.out.println("'令和2年10月19日'⇒LocalDate : " + convertStrToLocalDate("令和2年10月19日", "GGGGy年MM月dd日")); System.out.println("'20201019'⇒JapaneseDate : " + JapaneseDate.from(convertStrToLocalDate("20201019", "uuuuMMdd"))); } /** * 日付の文字列を日付型に変換した結果を返す * @param date 日付の文字列 * @param dateFormat 日付のフォーマット * @return 変換後の文字列 */ private static LocalDate convertStrToLocalDate(String date, String dateFormat){ if(StringCheckUtil.isEmpty(date) || StringCheckUtil.isEmpty(dateFormat)){ return null; } //暦体系は和暦体系で、日付と時刻を厳密に解決するスタイルで、 //DateTimeFormatterオブジェクトを作成 DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat, Locale.JAPAN) .withChronology(JapaneseChronology.INSTANCE) .withResolverStyle(ResolverStyle.STRICT); //日付の文字列をLocalDate型に変換して返却 return LocalDate.parse(date, df); } } |
要点まとめ
- Java8以降では、日付型にLocalDateTime型を利用し、日付のフォーマットとしてDateTimeFormatterを利用する。
- DateTimeFormatterでは、暦体系に和暦体系を指定したり、ResolverStyleにSTRICT(厳密)を指定したりする必要がある。