※当サイトの記事には、広告・プロモーションが含まれます。

CSVファイルをExcelで編集するとzero paddingが消失するので、Javaで日付のチェックについて考えてみた

japan.cnet.com

⇧ Oh, my gosh...

CSVファイルをExcelで編集するとzero paddingが消失するので、Javaで日付のチェックについて考えてみた

ダウンロードしたCSVファイルをExcelで編集した後に、アップロードしたら、何故か日付データのフォーマットチェックが失敗する事象が起きて、何でだろうと思ったのですが、

www.apro-soken.co.jp

Excelあるあるだったようです。

手掛けてるシステムが、CSVファイルをExcelで編集することを禁じるように周知しているのかは分からないのだけど、何か、編集されることを考慮した日付のフォーマットチェックにした方が良いのではないかと思ったので、考えてみました。

で、Javaで日付のフォーマットを考える場合、

  1.  \mathrm{yyyy/M/d}
  2.  \mathrm{yyyy/M/dd}
  3.  \mathrm{yyyy/MM/d}
  4.  \mathrm{yyyy/MM/dd}

の4パターンがあるのかなと、「/(スラッシュ)」が「-(ハイフン)」になってることもあるとは思うけども、年月日の区切りを「/(スラッシュ)」で考えます。

あとは、

qiita.com

⇧ 上記サイト様が仰るように、日付の値の妥当性を確認する必要もありますと、つまり、2023/2/30とか有り得ない日付の値をチェックして弾くことも必要ですと。

まとめると、

  1. 月日の桁数をチェックする
  2. 日付の値が妥当かチェックする

の2つを行う必要がありますと。

というわけで、Javaで日付チェックを実装してみました。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.util.Objects;
import java.util.regex.Pattern;

public class CheckDate {

	public static void main(String[] args) {
		// テストデータ
		String[] testDateStrList = {
		  "2023/1/1",
		  "2023/1/11",
		  "2023/11/1",
		  "2023/11/11",
		  "2023/01/1",
		  "2023/1/01",
		  "2023/01/01",
		  "2023/2/30",
		  "2023/a/1a",
		  "2023/111/111",
		  "20230/1/1",
		  "2023/1/1/"
		};
		
		// 日付チェックの実施と結果を表示
		for (int index = 0; index < testDateStrList.length; index++) {
			int formmatNo = selectDateFormmat(testDateStrList[index]);
			System.out.print(index + ", ");
			System.out.print(testDateStrList[index] + ", ");
			System.out.println(checkCorrectDateValue(testDateStrList[index], formmatNo));
		}
	}
	
	/**
	 * 日付のフォーマットをチェック
	 * @param dateStr 日付文字列
	 * @return 0:yyyy/M/d、1:yyyy/M/dd、2:yyyy/MM/d、3:yyyy/MM/dd、99:不正な日付フォーマット
	 */
	private static int selectDateFormmat(String dateStr) {
		
		if (Objects.isNull(dateStr) || dateStr.isEmpty()) {
			return 99;
		}
		
		final String regex_yyyyMd = "\\d{4}/\\d{1}/\\d{1}";
		final String regex_yyyyMdd = "\\d{4}/\\d{1}/\\d{2}";
		final String regex_yyyyMMd = "\\d{4}/\\d{2}/\\d{1}";
		final String regex_yyyyMMdd = "\\d{4}/\\d{2}/\\d{2}";
		
		Pattern pattern_yyyyMd = Pattern.compile(regex_yyyyMd);
		Pattern pattern_yyyyMdd = Pattern.compile(regex_yyyyMdd);
		Pattern pattern_yyyyMMd = Pattern.compile(regex_yyyyMMd);
		Pattern pattern_yyyyMMdd = Pattern.compile(regex_yyyyMMdd);

		if (pattern_yyyyMd.matcher(dateStr).matches()) {
			return 0;
		}
		if (pattern_yyyyMdd.matcher(dateStr).matches()) {
			return 1;
		}
		if (pattern_yyyyMMd.matcher(dateStr).matches()) {
			return 2;
		}
		if (pattern_yyyyMMdd.matcher(dateStr).matches()) {
			return 3;
		}
		return 99;
	}
	
	/**
	 * 日付の値の妥当性チェック
	 * @param dateStr 日付文字列
	 * @param selectFormmat 日付フォーマットを選択するための数値
	 * @return true:正当な日付、false:不正な日付
	 */
	private static boolean checkCorrectDateValue (String dateStr, int selectFormmat) {
		if (Objects.isNull(dateStr) || dateStr.isEmpty()) {
			return false;
		}
		try {
			switch (selectFormmat) {
			case 0:
				LocalDate.parse(dateStr,
					    DateTimeFormatter.ofPattern("uuuu/M/d").withResolverStyle(ResolverStyle.STRICT));
				return true;
			case 1:
				LocalDate.parse(dateStr,
					    DateTimeFormatter.ofPattern("uuuu/M/dd").withResolverStyle(ResolverStyle.STRICT));
				return true;
			case 2:
				LocalDate.parse(dateStr,
					    DateTimeFormatter.ofPattern("uuuu/MM/d").withResolverStyle(ResolverStyle.STRICT));
				return true;
			case 3:
				LocalDate.parse(dateStr,
					    DateTimeFormatter.ofPattern("uuuu/MM/dd").withResolverStyle(ResolverStyle.STRICT));
				return true;
			default:
				return false;
			}
		} catch (Exception e) {
			// 不正な日付の場合
			return false;
		}
	}

}

で、実行すると、

⇧ 日付のチェックが実行できました。

マジックナンバーを利用してしまっているので、改善が必要ですが、日付のチェック自体は機能してそうです。

Excelだと、日付以外にも、zero suppressされてしまうので、CSVファイルに保存するデータについてはzero paddingしないようにした方が良い気はしますかね。

と思ったんですが、

www.asobou.co.jp

⇧ 上記サイト様が仰るように、電話番号とか、0始まりのデータとかもあると考えると、対応が難しいってことですかね...

毎度モヤモヤ感が半端ない...

今回はこのへんで。