web-dev-qa-db-ja.com

時間APIを使用して文字列が日付パターンと一致するかどうかを確認するにはどうすればよいですか?

私のプログラムは、 LocalDate オブジェクトへの入力文字列を解析しています。ほとんどの場合、文字列は_30.03.2014_のように見えますが、_3/30/2014_のように見えることもあります。どちらに応じて、DateTimeFormatter.ofPattern(String pattern)を呼び出すために別のパターンを使用する必要があります。基本的に、解析を行う前に、文字列がパターン_dd.MM.yyyy_または_M/dd/yyyy_に一致するかどうかを確認する必要があります。

正規表現のアプローチは次のようになります。

_LocalDate date;
if (dateString.matches("^\\d?\\d/\\d{2}/\\d{4}$")) {
  date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("M/dd/yyyy"));  
} else {
  date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("dd.MM.yyyy"));  
}
_

これは機能しますが、文字列を照合するときにも日付パターン文字列を使用すると便利です。

新しいJava 8時間APIを使用して、正規表現のマッチングに頼らずにこれを行う標準的な方法はありますか?ドキュメントで DateTimeFormatter を調べました。 =しかし、何も見つかりませんでした。

13
user1019830

さて、私は先に進んで、それを答えとして投稿します。 1つの方法は、パターンを保持するクラスを作成することです。

public class Test {
    public static void main(String[] args){
        MyFormatter format = new MyFormatter("dd.MM.yyyy", "M/dd/yyyy");
        LocalDate  date = format.parse("3/30/2014"); //2014-03-30
        LocalDate  date2 = format.parse("30.03.2014"); //2014-03-30
    }
}

class MyFormatter {
    private final String[] patterns;

    public MyFormatter(String... patterns){
        this.patterns = patterns;
    }

    public LocalDate parse(String text){
        for(int i = 0; i < patterns.length; i++){
            try{
                return LocalDate.parse(text, DateTimeFormatter.ofPattern(patterns[i]));
            }catch(DateTimeParseException excep){}
        }
        throw new IllegalArgumentException("Not able to parse the date for all patterns given");
    }
}

@MenoHochschildが行ったように、コンストラクターに渡したDateTimeFormatterの配列からStringの配列を直接作成することで、これを改善できます。


もう1つの方法は、 DateTimeFormatterBuilder を使用して、必要な形式を追加することです。それを行うには他の方法がいくつかあるかもしれません、私はドキュメントを深く調べませんでした:-)

DateTimeFormatter dfs = new DateTimeFormatterBuilder()
                           .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd"))                                                                 
                           .appendOptional(DateTimeFormatter.ofPattern("dd.MM.yyyy"))                                                                                     
                           .toFormatter();
LocalDate d = LocalDate.parse("2014-05-14", dfs); //2014-05-14
LocalDate d2 = LocalDate.parse("14.05.2014", dfs); //2014-05-14
12
Alexis C.

@ZouZouのアプローチは可能な解決策です。

プログラムロジックの例外をできるだけ使用しないようにするために(パフォーマンス的にはそれほど良くありません)、次の 代替 が考慮される場合があります。

_static final String[] PATTERNS = {"dd.MM.yyyy", "M/dd/yyyy"};
static final DateTimeFormatter[] FORMATTERS = new DateTimeFormatter[PATTERNS.length];

static {
  for (int i = 0; i < PATTERNS.length; i++) {
    FORMATTERS[i] = DateTimeFormatter.ofPattern(PATTERNS[i]);
  }
}

public static LocalDate parse(String input) {
  ParsePosition pos = new ParsePosition();
  for (int i = 0; i < patterns.length; i++) {
    try {
      TemporalAccessor tacc = FORMATTERS[i].parseUnresolved(input, pos);
      if (pos.getErrorIndex < 0) {
        return LocalDate.from(tacc); // possibly throwing DateTimeException => validation failure
      }
    } catch (DateTimeException ex) { // catches also possible DateTimeParseException
      // go to next pattern
    }
    pos.setIndex(0);
    pos.setErrorIndex(-1);
  }
  throw new IllegalArgumentException("Input does not match any pattern: " + input);
}
_

メソッドの詳細parseUnresolved()

この方法は、解析の最初のフェーズのみを実行するため、予備的な検証や解析されたフィールドの結合作業を含む2番目のフェーズはありません。ただし、LocalDate.from()はすべての入力を検証するので、これで十分だと思います。そして利点は、parseUnresolved()ParsePositionのエラーインデックスを使用することです。これは、従来の_Java.text.Format_-動作と一致しています。

残念ながら、代替のより直感的なメソッド DateTimeFormater.parse() は、最初にDateTimeParseExceptionを作成し、次にこの例外にエラーインデックスを格納します。そこで、不必要な例外の発生を避けるために、この方法を使用しないことにしました。私にとって、このAPIの詳細は疑わしい設計上の決定です。

0
Meno Hochschild