1. 概要

このチュートリアルでは、StringにJavaの有効な日付が含まれているかどうかを確認するさまざまな方法について説明します。

Java 8の前、Java 8の後、および Apache CommonsValidatorを使用したソリューションを見ていきます。

2. 日付検証の概要

アプリケーションでデータを受信するときはいつでも、それ以上の処理を行う前に、そのデータが有効であることを確認する必要があります。

日付入力の場合、以下を確認する必要がある場合があります。

  • 入力には、MM / DD/YYYYなどの有効な形式の日付が含まれています。
  • 入力のさまざまな部分が有効な範囲内にあります。
  • 入力はカレンダーの有効な日付に解決されます。

正規表現を使用して上記を行うことができます。 ただし、さまざまな入力形式とロケールを処理するための正規表現は複雑で、エラーが発生しやすくなります。 また、パフォーマンスが低下する可能性があります。

柔軟で堅牢かつ効率的な方法で日付検証を実装するさまざまな方法について説明します。

まず、日付検証用のインターフェースを作成しましょう。

public interface DateValidator {
   boolean isValid(String dateStr);
}

次のセクションでは、さまざまなアプローチを使用してこのインターフェイスを実装します。

3. DateFormatを使用して検証します

Javaは、最初から日付をフォーマットおよび解析する機能を提供してきました。 この機能は、 DateFormat abstractクラスとその実装— SimpleDateFormatにあります。

DateFormatクラスのparseメソッドを使用して日付検証を実装しましょう。

public class DateValidatorUsingDateFormat implements DateValidator {
    private String dateFormat;

    public DateValidatorUsingDateFormat(String dateFormat) {
        this.dateFormat = dateFormat;
    }

    @Override
    public boolean isValid(String dateStr) {
        DateFormat sdf = new SimpleDateFormat(this.dateFormat);
        sdf.setLenient(false);
        try {
            sdf.parse(dateStr);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }
}

DateFormatおよび関連するクラスはスレッドセーフではないため、メソッド呼び出しごとに新しいインスタンスを作成しています。

次に、このクラスの単体テストを作成しましょう。

DateValidator validator = new DateValidatorUsingDateFormat("MM/dd/yyyy");

assertTrue(validator.isValid("02/28/2019"));        
assertFalse(validator.isValid("02/30/2019"));

これは、Java8以前の最も一般的なソリューションでした。

4. LocalDateを使用して検証します

Java 8では、改良された日時APIが導入されました。 追加しました LocalDateクラス。時間なしの日付を表します。 このクラスは不変でスレッドセーフです。

LocalDate は、日付を解析するための2つの静的メソッドを提供し、どちらもDateTimeFormatterを使用して実際の解析を実行します。

public static LocalDate parse​(CharSequence text)
// parses dates using using DateTimeFormatter.ISO_LOCAL_DATE

public static LocalDate parse​(CharSequence text, DateTimeFormatter formatter)
// parses dates using the provided formatter

parse メソッドを使用して、日付検証を実装しましょう。

public class DateValidatorUsingLocalDate implements DateValidator {
    private DateTimeFormatter dateFormatter;
    
    public DateValidatorUsingLocalDate(DateTimeFormatter dateFormatter) {
        this.dateFormatter = dateFormatter;
    }

    @Override
    public boolean isValid(String dateStr) {
        try {
            LocalDate.parse(dateStr, this.dateFormatter);
        } catch (DateTimeParseException e) {
            return false;
        }
        return true;
    }
}

実装では、フォーマットにDateTimeFormatterオブジェクトを使用します。 このクラスはスレッドセーフであるため、異なるメソッド呼び出しで同じインスタンスを使用しています。

この実装の単体テストも追加しましょう。

DateTimeFormatter dateFormatter = DateTimeFormatter.BASIC_ISO_DATE;
DateValidator validator = new DateValidatorUsingLocalDate(dateFormatter);
        
assertTrue(validator.isValid("20190228"));
assertFalse(validator.isValid("20190230"));

5. DateTimeFormatterを使用して検証します

前のセクションで、LocalDateが解析にDateTimeFormatterオブジェクトを使用することを確認しました。 DateTimeFormatter クラスを直接使用して、フォーマットと解析を行うこともできます。

DateTimeFormatterは、テキストを2つのフェーズで解析します。フェーズ1では、構成に基づいてテキストをさまざまな日付と時刻のフィールドに解析します。 フェーズ2では、解析されたフィールドを日付および/または時刻オブジェクトに解決します。

ResolverStyle属性はフェーズ2を制御します。 これは、3つの可能な値を持つ列挙型です。

  • LENIENT –日付と時刻を寛大に解決します
  • SMART –インテリジェントな方法で日付と時刻を解決します
  • STRICT –日付と時刻を厳密に解決します

次に、DateTimeFormatterを直接使用して日付検証を記述しましょう。

public class DateValidatorUsingDateTimeFormatter implements DateValidator {
    private DateTimeFormatter dateFormatter;
    
    public DateValidatorUsingDateTimeFormatter(DateTimeFormatter dateFormatter) {
        this.dateFormatter = dateFormatter;
    }

    @Override
    public boolean isValid(String dateStr) {
        try {
            this.dateFormatter.parse(dateStr);
        } catch (DateTimeParseException e) {
            return false;
        }
        return true;
    }
}

次に、このクラスの単体テストを追加しましょう。

DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.US)
    .withResolverStyle(ResolverStyle.STRICT);
DateValidator validator = new DateValidatorUsingDateTimeFormatter(dateFormatter);
        
assertTrue(validator.isValid("2019-02-28"));
assertFalse(validator.isValid("2019-02-30"));

上記のテストでは、パターンとロケールに基づいてDateTimeFormatterを作成しています。 日付には厳密な解像度を使用しています。

6. ApacheCommonsValidatorを使用して検証する

Apache Commons プロジェクトは、検証フレームワークを提供します。 これには、日付、時刻、数値、通貨、IPアドレス、電子メール、URLなどの検証ルーチンが含まれています。

この記事では、 GenericValidator クラスを見てみましょう。このクラスは、Stringに有効な日付が含まれているかどうかを確認するためのいくつかのメソッドを提供します。

public static boolean isDate(String value, Locale locale)
  
public static boolean isDate(String value,String datePattern, boolean strict)

ライブラリを使用するには、 commons-validatorMaven依存関係をプロジェクトに追加しましょう。

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.6</version>
</dependency>

次に、GenericValidatorクラスを使用して日付を検証しましょう。

assertTrue(GenericValidator.isDate("2019-02-28", "yyyy-MM-dd", true));
assertFalse(GenericValidator.isDate("2019-02-29", "yyyy-MM-dd", true));

7. 結論

この記事では、Stringに有効な日付が含まれているかどうかを確認するさまざまな方法について説明しました。

いつものように、完全なソースコードはGitHubにあります。