none
特定の曜日が含まれる日付文字列のDateTime.Parseがエラーとなる RRS feed

  • 質問

  • Windowsのロケール設定にて短い日付書式に曜日を設定した場合、日と月のみ日付文字列のParseに失敗します。

    これは.NET Frameworkの問題でしょうか?修正の目処は立っているのでしょうか?

    尚、英語環境の場合、及び、曜日表示にdddの代わりにddddを使用した場合は発生しません。

    【エラー内容】

     Exception: System.FormatException
     Message: 文字列は有効な DateTime ではありませんでした。
     Source: mscorlib
        場所 System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)


    【発生環境】

     Windows 10 Pro

     .NET Framework 4.6.2

     Visual Studio 2017 Professional

    【テストコード】

     ※日と月のみFalseになる。(=Parseできない)

        class Program
        {
            static void Main(string[] args)
            {
                var _date = new DateTime(2019, 1, 1);
                for (int i = 0; i < 365; i++)
                {
                    OutputDate(_date.ToString());
                    _date = _date.AddDays(1);
                }

                Console.ReadKey();
            }

            private static void OutputDate(string date)
            {
                DateTime _temp = new DateTime();
                var _output = date + "\t" + DateTime.TryParse(date, out _temp);
                Console.WriteLine(_output);
            }
        }


    【ロケール設定内容】

     日付(短い形式): yyyy/MM/dd ddd




    • 編集済み kk620 2019年10月2日 7:13
    2019年10月2日 6:52

回答

  • 日付(短い形式): yyyy/MM/dd ddd

    書式指定が「yyyy/MM/dd' ('ddd')'」であれば大丈夫だったのかな…。

     

    自由な書式指定を許容してしまうと、文字列への変換ができたとしても、それを日付に復元できるとは限りませんよね。日付→文字列→日付と再パースする必要があるのなら、OS 設定に依存させず、アプリケーション依存の書式指定に固定すべきかと思いますよ。

    つまり _date.ToString(fmt) で出力して、復元時は TryParse ではなく TryParseExact を使う形で対応するという事で。

    なお、引数無しの _date.ToString() で出力される場合のフォーマット は、下記で取得できそうです。

    var culture = System.Threading.Thread.CurrentThread.CurrentCulture;
    var info = (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo));
    string fmt = $"{info.ShortDatePattern} {info.LongTimePattern}";

    それを使って復元する場合はこんな感じです。
    あるいは配列を受け取る方のオーバーロードを使って、複数のフォーマットを許容させてもよいかと思います。

    // var _output = date + "\t" + DateTime.TryParse(date, out _temp);
    var _output = date + "\t" + DateTime.TryParseExact(date, fmt, null, DateTimeStyles.None, out _temp);

    • 回答としてマーク kk620 2019年10月2日 9:11
    2019年10月2日 8:09

すべての返信

  • 日付(短い形式): yyyy/MM/dd ddd

    書式指定が「yyyy/MM/dd' ('ddd')'」であれば大丈夫だったのかな…。

     

    自由な書式指定を許容してしまうと、文字列への変換ができたとしても、それを日付に復元できるとは限りませんよね。日付→文字列→日付と再パースする必要があるのなら、OS 設定に依存させず、アプリケーション依存の書式指定に固定すべきかと思いますよ。

    つまり _date.ToString(fmt) で出力して、復元時は TryParse ではなく TryParseExact を使う形で対応するという事で。

    なお、引数無しの _date.ToString() で出力される場合のフォーマット は、下記で取得できそうです。

    var culture = System.Threading.Thread.CurrentThread.CurrentCulture;
    var info = (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo));
    string fmt = $"{info.ShortDatePattern} {info.LongTimePattern}";

    それを使って復元する場合はこんな感じです。
    あるいは配列を受け取る方のオーバーロードを使って、複数のフォーマットを許容させてもよいかと思います。

    // var _output = date + "\t" + DateTime.TryParse(date, out _temp);
    var _output = date + "\t" + DateTime.TryParseExact(date, fmt, null, DateTimeStyles.None, out _temp);

    • 回答としてマーク kk620 2019年10月2日 9:11
    2019年10月2日 8:09
  • ご回答ありがとうございます。

    大変参考になりました。

    2019年10月2日 9:11