2017-12-27 23 views
4

私の要件は、日付文字列が、指定された有効なフォーマットのセットに基づいて正しいフォーマットであることを検証することです。Java 8 DateTimeFormatterBuilder()。appendOptional not working

有効な形式:

MM/dd/yy 
MM/dd/yyyy 

私は複数のオプションのフォーマットをサポートする柔軟なフォーマッタを作成するためのJava 8 DateTimeFormatterBuilderを使用して、簡単な試験方法を作成しました。ここでは、コードです:私はこれを実行すると

public static void test() { 
    DateTimeFormatter formatter = new DateTimeFormatterBuilder() 
      .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yy")) 
      .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yyyy")) 
      .toFormatter(); 

    String dateString = "10/30/2017"; 

    try { 
     LocalDate.parse(dateString, formatter); 
     System.out.println(dateString + " has a valid date format"); 
    } catch (Exception e) { 
     System.out.println(dateString + " has an invalid date format"); 
    } 
} 

、ここで出力されているが、

10/30/2017 has an invalid date format 

あなたがコードで見たよう、有効な日付フォーマットであるMM/DD/YYとMM/DD/yyyy。 私は、10/30/2017の日付がMM/dd/yyyyと一致するので有効であると予想しました。ただし、2011年10月30日は無効と報告されています。

何が問題になりますか?なぜこれは機能しないのですか?

私も

.appendOptional(DateTimeFormatter.ofPattern("MM/dd/yy")) 
.appendOptional(DateTimeFormatter.ofPattern("MM/dd/yyyy")) 

の代わりに

​​

を試してみましたが、それでも同じ問題がありました。

予想通りこのコードは、私が使用している場合に実行されます。

String dateString = "10/30/17"; 

String dateString = "10/30/2017"; 

の代わりに、私はここで間違って起こっている2つの質問

  1. がありますか?なぜ「10/30/2010」では機能しないのですか?

  2. Java 8を使用すると、柔軟な日付フォーマッタ(複数のオプションの書式をサポートするフォーマッタ)を正しく作成する方法はありますか?私はパターン文字列自体にオプションのセクションを作成するために[]を使用することを知っています。私は、フォーマッタは、あなたが期待するように動作しません。私は(パターン文字列内の[]を回避し、それぞれ別々のフォーマット文字列のために別のオプション句を使用して)しようとしていたものと類似のもの

+0

'appendOptionalは()'(以下私の答えを参照してください)を使用することを想定されていない方法:ここではイラストです。日付の形式を変えるには、代わりにフォーマッタのリストを作成するのが最も簡単な方法ですが、これが最善の方法であるかどうかはわかりません。 –

答えて

3

を探していますオプションの一部は、余分なものがあるならば、それは第二と一致する必要が

  • 、第一のパターン(例えば、「MM/DD/YY」)に添付の余分なものがない場合、それは結構です

    • を意味し、パターン(例えば、それは少し明確にするにはグラム、 "MM/DD/YYYY")

    、それをよりよく理解するために、次のサンプルコードを実行しよう:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder() 
          .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yy")) 
          .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yyyy")) 
          .toFormatter(); 
    
        String[] dateStrings = { 
          "10/30/17",   // valid 
          "10/30/2017",   // invalid 
          "10/30/1710/30/2017", // valid 
          "10/30/201710/30/17" // invalid 
        }; 
    
        for (String dateString : dateStrings) { 
         try { 
          LocalDate.parse(dateString, formatter); 
          System.out.println(dateString + " has a valid date format"); 
         } catch (Exception e) { 
          System.err.println(dateString + " has an invalid date format"); 
         } 
        } 
    

    ==

    10/30/17 has a valid date format 
    10/30/1710/30/2017 has a valid date format 
    10/30/2017 has an invalid date format 
    10/30/201710/30/17 has an invalid date format 
    

    ==

    これは単なる解決策であり、パフォーマンスが懸念される場合は、解析例外をキャッチすることによる検証はlasトンなど、あなたが最初にあなたは、ループのための簡単なを含む方法でストリームを置き換えることが

  • を解析する日付文字列を実行する前に、長さや正規表現で文字列をチェックして

    • を訴える

      String[] patterns = { "MM/dd/yy", "MM/dd/yyyy" }; 
      Map<String, DateTimeFormatter> formatters = Stream.of(patterns).collect(Collectors.toMap(
           pattern -> pattern, 
           pattern -> new DateTimeFormatterBuilder().appendOptional(DateTimeFormatter.ofPattern(pattern)).toFormatter() 
      )); 
      
      String dateString = "10/30/17"; 
      boolean valid = formatters.entrySet().stream().anyMatch(entry -> { 
          // relying on catching parsing exception will have serious expense on performance 
          // a simple check will already improve a lot 
          if (dateString.length() == entry.getKey().length()) { 
           try { 
            LocalDate.parse(dateString, entry.getValue()); 
            return true; 
           } 
           catch (DateTimeParseException e) { 
            // ignore or log it 
           } 
          } 
          return false; 
      }); 
      
  • +0

    ラップトップでは答えが消えてしまいますが、OP *で使用するコードを入力した方が良いでしょう。 –

    0

    この場合、ビルダーのappendValueReduced()メソッドが設計されています。

    フィールドのための完全な値を解析する場合、フォーマッタは、絶対値として扱います。

    フィールドのための部分的な値を解析すると、フォーマッタが指定したベースに、それは相対的な解釈します。たとえば、1970年から2069年の間に2桁の年を解釈する場合は、1970年をベースとして指定できます。

    LocalDate century = LocalDate.ofEpochDay(0); /* Beginning Jan. 1, 1970 */ 
        DateTimeFormatter f = new DateTimeFormatterBuilder() 
          .append(DateTimeFormatter.ofPattern("MM/dd/")) 
          .appendValueReduced(ChronoField.YEAR, 2, 4, century) 
          .toFormatter(); 
        System.out.println(LocalDate.parse("10/30/2017", f)); /* 2017-10-30 */ 
        System.out.println(LocalDate.parse("10/30/17", f)); /* 2017-10-30 */ 
        System.out.println(LocalDate.parse("12/28/1969", f)); /* 1969-12-28 */ 
        System.out.println(LocalDate.parse("12/28/69", f)); /* 2069-12-28 */