2017-03-20 12 views
4

SimpleDateFormatとDateを使用して従来のコードを置き換えようとすると、java.time.DateTimeFormatterとLocalDateを使用するときに問題が発生しました。 2つの日付形式は同等ではありません。この時点で、私は2つの日付の種類が同じではないことを知っていなければなりませんが、私が考えているシナリオは時間の面を気にしないので、無視することができます。同じパターンがてDateTimeFormatterあなたはSDFのと同等の日付を見ることを期待したいヌルを生成するまでの両端フォーマッタで使用されるとき、あなたが見ることができるようにSimpleDateFormatをDateTimeFormatterに変換する

public Date getDate(String value) { 
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); 
    try { 
     return dateFormat.parse(value); 
    } catch (ParseException e) { 
     return null; 
    } 
} 

public LocalDate getLocalDate(String value) { 
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); 
    try { 
     return LocalDate.parse(value, formatter); 
    } catch (DateTimeParseException e) { 
     return null; 
    } 
} 

public void testDates() { 
    getDate("03/07/2016");    // Sun Jul 03 00:00:00 BST 2016 
    getDate("3/7/2016");     // Sun Jul 03 00:00:00 BST 2016 
    getDate("3/7/2016 00:00:00");  // Sun Jul 03 00:00:00 BST 2016 
    getDate("3/7/2016 00:00:00.0+0100"); // Sun Jul 03 00:00:00 BST 2016 
    getDate("3/7/2016T00:00:00.0+0100"); // Sun Jul 03 00:00:00 BST 2016 

    getLocalDate("03/07/2016");    // 2016-07-03 
    getLocalDate("3/7/2016");     // null 
    getLocalDate("3/7/2016 00:00:00");  // null 
    getLocalDate("3/7/2016 00:00:00.0+0100"); // null 
    getLocalDate("3/7/2016T00:00:00.0+0100"); // null 
} 

。このシナリオでは、不要なデータは削除されると予想しますが、そうではありません。

堅牢な日付/時刻パーサーを作成するにはどうすればいいですか?

+2

私は 'DD/MM/yyyy'は明らかに月の日に2桁、月2桁、年のために4桁の数字を必要とするため、' SimpleDateFormat'は、より堅牢ではないと思います。入力がこの要件と一致しない場合、フレームワークは解析例外を発生させる必要があります。ユーザーの要件と異なる変換を行うことは危険です。 –

+1

はいSDFが壊れましたが、コードはこれに依存しています。ですから一般的に私はAPIが固定フォーマットでなければならないと完全に同意しますが、このシナリオではファイルを解析していて、人々はさまざまなフォーマットで日付を提供することができます。コードはそれらをすべて満たす必要があります。明らかに、これは直面している問題の抜粋に過ぎません。実際には日付順やセパレータの周りにはたくさんのチェックがあります。 – Remlap21

答えて

3

これには他の回答があるかもしれませんが、私が出てきたことは、私が持っている最も極端な場合に対応しています。まず、dd/MMをd/Mに減らしました。これは予想される文字数の最小値を示します。したがって、2桁の数字を完全に細かく解析します。新しいDateTimeFormatterBuilder()。parseLenient()を使用することもできますが、これは不要なようです。

第2に、フォーマットパターン自体にオプションの節を使用することにしました。これにより、私が解決しようとしていた部分とまったく同じではない部分を指定することができます。で私たちを残し

DateTimeFormatter.ofPattern(d/M/yyyy[' ']['T'][H:mm[:ss[.S]]][X]); 

は、これが今のオフセットTセパレータ、秒、ミリ秒とゾーンを含む時間の有無にかかわらず、日付を提供する処理します。

運が良ければ、これは他の人に役立ちます!

private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy[' ']['T'][H:mm[:ss[.S]]][X]"); 

public LocalDate getRobustLocalDate(String value) { 
    try { 
     return LocalDate.parse(value, formatter); 
    } catch (DateTimeParseException e) { 
     return null; 
    } 
} 

@Test 
public void testDates() { 
    getRobustLocalDate("03/07/2016");    // 2016-07-03 
    getRobustLocalDate("3/7/2016");     // 2016-07-03 
    getRobustLocalDate("3/7/2016 00:00:00");  // 2016-07-03 
    getRobustLocalDate("3/7/2016 00:00:00.0+0100"); // 2016-07-03 
    getRobustLocalDate("3/7/2016T00:00:00.0+0100"); // 2016-07-03 
} 
+1

メソッドを呼び出すたびに 'DateTimeFormatter'を初期化する必要はありません。' DateTimeFormatter'クラスのインスタンスは不変であるため、メソッドの外に保存して再利用することができ、オブジェクト生成とパターン解析に少し費やすことができます。あなたのパターンは変わらないので、これが有効な調整であると感じます。 –

+0

ええ - 完全に同意する、それはテストの目的のためにちょうどこのようだった。それを他人に明瞭にするために編集する – Remlap21