web-dev-qa-db-ja.com

フォーマットを知らずに文字列を日付に変換する方法は?

私は問題があります。一部の文字列を日付に変換しようとしていますが、日付の形式がわかりません。

yyyy.mm.dd hh:mm:ssまたはMM.dd.yy hh:mm:ss 等々。

これらの文字列を日付に変換するにはどうすればよいですか?私はこれを試しました:

DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
Date d = (Date)formatter.parse(someDate);

しかし、someDateを出力すると、2010-08-05 12:42:48.638 CEST、つまりyyyy.mm.dd hh:mm:ssただし、上記のコードを実行すると、日付オブジェクトはSat Jan 31 00:42:48 CET 11これは控えめに言っても奇妙です。

文字列を現在まで正しくフォーマットする方法はありますか?

41
Shervin Asgari

私は、一般的な場合には正しい解決策がないというクラゲンに同意します。ただし、次の条件が当てはまる場合は、以下のソリューションを使用できます。

  1. すべての可能な形式のセットがあります

  2. フォーマット間にあいまいさはありません。それらのうちの2つでは日付式を正常に解析できません。

可能な形式のリストを反復処理する次のソリューションを検討してください。このソリューションでは、マルチスレッド環境で日付の解析を効率的にするために、 ThreadLocal を使用します(SimpleDateFormatはスレッドセーフではないことに注意してください)。

public class FlexibleDateParser {
    private List<ThreadLocal<SimpleDateFormat>> threadLocals = new  ArrayList<ThreadLocal<SimpleDateFormat>>();

    public FlexibleDateParser(List<String> formats, final TimeZone tz){
        threadLocals.clear();
        for (final String format : formats) {
            ThreadLocal<SimpleDateFormat> dateFormatTL = new ThreadLocal<SimpleDateFormat>() {
                protected SimpleDateFormat initialValue() {
                    SimpleDateFormat sdf = new SimpleDateFormat(format);
                    sdf.setTimeZone(tz); 
                    sdf.setLenient(false);
                    return sdf;
                }
            };
            threadLocals.add(dateFormatTL);
        }       
    }

    public Date parseDate(String dateStr) throws ParseException {
        for (ThreadLocal<SimpleDateFormat> tl : threadLocals) {
            SimpleDateFormat sdf = tl.get();
            try {
                return sdf.parse(dateStr);
            } catch (ParseException e) {
                // Ignore and try next date parser
            }
        }
        // All parsers failed
        return null;
    }       
}
11
Eyal Schneider

前述のように、少なくともパターン候補の順序付きリストが必要です。それができたら、 Apache DateUtils にはparseDate(String dateString, String[] patterns)メソッドがあり、日付文字列のパターンのリストを簡単に試して、一致する最初の文字列で解析できます。

public static Date parseDate(String str,
                         String[] parsePatterns)
                  throws ParseException

さまざまなパーサーを試行して、日付を表す文字列を解析します。

解析は、各解析パターンを順番に試行します。解析は、入力文字列全体を解析する場合にのみ成功と見なされます。解析パターンが一致しない場合、ParseExceptionがスローされます。

パーサーは、解析された日付に対して寛容になります。

7
oksayt

アメリカの日付形式に基づいた迅速で汚れたソリューションを次に示します。

public Date parseDate(String strDate) throws Exception
{
    if (strDate != null && !strDate.isEmpty())
    {
        SimpleDateFormat[] formats =
                new SimpleDateFormat[] {new SimpleDateFormat("MM-dd-yyyy"), new SimpleDateFormat("yyyyMMdd"),
                        new SimpleDateFormat("MM/dd/yyyy")};

        Date parsedDate = null;

        for (int i = 0; i < formats.length; i++)
        {
            try
            {
                parsedDate = formats[i].parse(strDate);
                return parsedDate;
            }
            catch (ParseException e)
            {
                continue;
            }
        }
    }
    throw new Exception("Unknown date format: '" + strDate + "'");
}
4
bjoern

問題は国際化に関連しています。 Kragenが答えたように、未知の形式で日付を解析することはできません。ただし、可能なすべてのロケールをスキャンしてsomethingを解析できますが、正しく解析されたかどうかはわかりません。

ほんの少しの国際化の背景:

Q:この日付が何月何年を指しているのか教えてください:

09/11/10?

A:ロケールを知らないと、できません。それは何でもかまいません。 9月11日、米国。 11月9日、イギリス。等々。

4
Paweł Dyda

プロトコルの場合;フォーマットを定義する-おそらく、スウェーデンの私たち以外の人を苛立たせるISO ...

ユーザーから入力した場合;ロケールを設定します。できる場合は、2009年11月10日のように、解析された日付を完全な形式で表示して、ユーザーが検証できるようにします。

1
KarlP

ここに私のために働いている簡単な解決策があります。これは、日付を解析し、文字列を引数として渡し、必要な形式で解析する簡単な方法です。

String dateToConvert(String date) {
        String strDate = "";
        try {
            //create SimpleDateFormat object with source string date format
            DateFormat sdfSource = new SimpleDateFormat("yyyy-MM-dd");

            //parse the string into Date object
            Date d = sdfSource.parse(date);
            LocalLog.e(LOG_TAG, d.toString());
            //create SimpleDateFormat object with desired date format
            SimpleDateFormat sdfDestination = new SimpleDateFormat(AppConstants.UNIVERSAL_DATE_FORMAT);

            //parse the date into another format
            strDate = sdfDestination.format(d);

            LocalLog.e(LOG_TAG, strDate);

        } catch (ParseException pe) {
            System.out.println("Parse Exception : " + pe);
        }
        return strDate;
    }
0

私の唯一の推測は、まずフォーマットを把握するためにいくつかの統計を収集する必要があるということです。

運が良ければ、「2010/08/13」のような日付があり、明確に解析できます

0

この回答は、この質問の複製としてマークされている別の質問に対する私の回答のコピーです

私はかつて、日付の形式が事前にわからなかった現在までの文字列を解析するコードを書く仕事をしました。つまり有効な日付形式を解析する必要がありました。私はプロジェクトを書き、その後、実装の背後にあるアイデアを説明する記事を書きました。記事へのリンクは次のとおりです。 Java 8 Java.timeパッケージ:現在の文字列を解析する 。一般的なアイデアは、サポートするすべてのパターンを外部プロパティファイルに書き込み、そこからそれらを読み取り、成功するかフォーマットがなくなるまで、それらのフォーマットで文字列を1つずつ解析しようとすることです。一部の文字列はいくつかの形式で有効な場合があるため、順序も重要であることに注意してください(米国/ヨーロッパの違い)。利点は、コードを変更せずにファイルにフォーマットを追加/削除し続けることができることです。そのため、このようなプロジェクトは異なる顧客向けにカスタマイズすることもできます

0
Michael Gantman