web-dev-qa-db-ja.com

文字列をC#のDateTimeに解析する

そのようにフォーマットされた文字列に日付と時刻があります。

"2011-03-21 13:26" //year-month-day hour:minute

どうやってそれをSystem.DateTimeにパースできますか?

手動で日付のフォーマットを指定できるように、可能であればDateTime.Parse()DateTime.ParseExact()のような関数を使いたいです。

140
Hooch

DateTime.Parse()は与えられた日付のフォーマットを見つけようとします、そしてそれは通常良い仕事をします。あなたが日付が常に与えられたフォーマットになることを保証できるならば、あなたはParseExact()を使うことができます:

string s = "2011-03-21 13:26";

DateTime dt = 
    DateTime.ParseExact(s, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);

(ただし、日付の形式が正しくない場合は、通常TryParseメソッドのいずれかを使用するほうが安全です)。

フォーマット文字列を作成するときは、 カスタムの日付と時刻のフォーマット文字列 を必ず確認してください。

C#形式の文字列に関するもう1つの便利なリソースは、 C#での文字列フォーマット です。

233
Mitch Wheat

後で説明するように、私は常にTryParseおよびTryParseExactメソッドを優先します。使用するには少しかさばるので、解析をはるかに簡単にする拡張メソッドを記述しました。

var    dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");

ParseParseExactなどとは異なり、例外はスローされず、経由で確認できます。

if (dt.HasValue) { // continue processing } else { // do error handling }

変換が成功したかどうか(この場合dtにはdt.Valueを介してアクセスできる値があります)かどうか(この場合はnullです)。

これにより、「エルビス」演算子?.のようなエレガントなショートカットを使用することもできます。例:

int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;

ここでは、year.HasValueを使用して、変換が成功したかどうかを確認することもできます。成功しなかった場合、yearにはnullが含まれます。変換が失敗した場合にスローされる例外はありません。


解決策:.ToDate()拡張メソッド

。NetFiddleで試してみてください

public static class Extensions
{
    // Extension method parsing a date string to a DateTime?
    // dateFmt is optional and allows to pass a parsing pattern array
    // or one or more patterns passed as string parameters
    public static DateTime? ToDate(this string dateTimeStr, params string[] dateFmt)
    {
      // example: var dt = "2011-03-21 13:26".ToDate(new string[]{"yyyy-MM-dd HH:mm", 
      //                                                  "M/d/yyyy h:mm:ss tt"});
      // or simpler: 
      // var dt = "2011-03-21 13:26".ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
      const DateTimeStyles style = DateTimeStyles.AllowWhiteSpaces;
      if (dateFmt == null)
      {
        var dateInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat;
        dateFmt=dateInfo.GetAllDateTimePatterns();
      }
      // Commented out below because it can be done shorter as shown below.
      // For older C# versions (older than C#7) you need it like that:
      // DateTime? result = null;
      // DateTime dt;
      // if (DateTime.TryParseExact(dateTimeStr, dateFmt,
      //    CultureInfo.InvariantCulture, style, out dt)) result = dt;
      // In C#7 and above, we can simply write:
      var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
                   style, out var dt) ? dt : null as DateTime?;
      return result;
    }
}

コードに関する情報

なぜ私がInvariantCulture呼び出しTryParseExactを使用したのか疑問に思うかもしれません:これは、関数にフォーマットパターンを常に同じように処理させるためです(そうでなければ、たとえば "。"は英語の小数点区切りとして解釈されます)グループ区切り文字ですorドイツ語の日付区切り文字)。数行前に既にカルチャーベースのフォーマット文字列を照会したことを思い出してください。ここでは大丈夫です。

更新:.ToDate()(パラメータなし)は、スレッドの現在のカルチャのすべての一般的な日付/時刻パターンにデフォルト設定されます。
resultでは許可されないため、dtTryParseExactを一緒に必要とすることに注意してくださいDateTime?を使用します。これを返す予定です。 C#バージョン7では、ToDate関数を次のように少し単純化できます。

 // in C#7 only: "DateTime dt;" - no longer required, declare implicitly
 if (DateTime.TryParseExact(dateTimeStr, dateFmt,
     CultureInfo.InvariantCulture, style, out var dt)) result = dt;

または、さらに短くしたい場合:

 // in C#7 only: Declaration of result as a "one-liner" ;-)
 var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
              style, out var dt) ? dt : null as DateTime?;

この場合、2つの宣言DateTime? result = null;DateTime dt;はまったく必要ありません-1行のコードで実行できます。 (必要に応じて、out DateTime dtの代わりにout var dtを書き込むことも許可されます)。

paramsキーワードを使用して、コードをさらに簡素化しました。2は不要になりましたnd オーバーロードされたメソッド。


使用例

var dtStr="2011-03-21 13:26";    
var dt=dtStr.ToDate("yyyy-MM-dd HH:mm");
if (dt.HasValue)
{
    Console.WriteLine("Successful!");
    // ... dt.Value now contains the converted DateTime ...
}
else
{
    Console.WriteLine("Invalid date format!");
}

ご覧のとおり、この例ではdt.HasValueを照会して、変換が成功したかどうかを確認します。追加のボーナスとして、TryParseExactでは厳密なDateTimeStylesを指定できるため、適切な日付/時刻文字列が渡されたかどうかを正確に知ることができます。


その他の使用例

オーバーロード関数を使用すると、日付の解析/変換に使用される有効な形式の配列配列を渡すことができます here 同様に(TryParseExactはこれを直接サポートします)、例えば.

string[] dateFmt = {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt", 
                     "MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss", 
                     "M/d/yyyy hh:mm tt", "M/d/yyyy hh tt", 
                     "M/d/yyyy h:mm", "M/d/yyyy h:mm", 
                     "MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"};
var dtStr="5/1/2009 6:32 PM"; 
var dt=dtStr.ToDate(dateFmt);

少数のテンプレートパターンしかない場合は、次のように書くこともできます。

var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");

高度な例

??演算子を使用して、デフォルトでフェイルセーフ形式、たとえば.

var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");

この場合、.ToDate()は一般的なローカルカルチャ日付形式を使用し、これらすべてが失敗した場合は、フォールバックとして ISO標準 format "yyyy-MM-dd HH:mm:ss"を使用しようとします。このように、拡張機能により、さまざまなフォールバック形式を簡単に「連鎖」させることができます。

LINQで拡張機能を使用することもできます。これを試してください(上記の.NetFiddleにあります)。

var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
(new[] { "15-01-2019", "15.01.2019" }).Select(s => s.ToDate(patterns)).Dump(); 

パターンを使用してその場で配列の日付をオンザフライに変換し、コンソールにダンプします。


TryParseExactの背景

最後に、背景についてのコメントをいくつか示します(つまり、このように書いた理由)。

私はこの拡張メソッドでTryParseExactを好んでいます、なぜならあなたは例外処理を避けるためです -できます 例外についてのEric Lippertの記事を読んでください なぜParseではなくTryParseを使用する必要があるのか​​、そのトピックについて彼に引用します:2)

この残念なデザインの決定1) [注釈:Parseメソッドが例外をスローできるようにする]がとても厄介だったので、フレームワークチームはすぐにTryParseを実装しましたこれは正しいことです。

ただし、TryParseTryParseExactはどちらも使用するのがあまり快適ではありません。初期化されていない変数をoutパラメーターとして使用するように強制します。 '変換している場合、ブール値の戻り値を評価する必要があります-ifstatementをすぐに使用するか、戻り値を追加のブール変数に保存して後でチェックできるようにする必要があります。そして、変換が成功したかどうかを知らずにターゲット変数を使用することはできません。

ほとんどの場合、知りたいのは変換が成功したかどうか(そしてもちろん成功した場合は値)なので、nullableターゲット変数すべての情報を保持することが望ましいとはるかにエレガントになります-情報全体が1か所に保存されるためです:それは一貫性があり、使いやすく、エラーが少ないです。

私が書いた拡張メソッドはまさにそれを行います(使用しない場合は毎回どのようなコードを書かなければならないかを示しています)。

.ToDate(strDateFormat)の利点は、元のDateTime.Parseのようにシンプルできれいに見えることですが、変換が成功したかどうかを確認し、例外をスローしないことです。


1) ここで意味するのは、例外処理(つまりtry { ... } catch(Exception ex) { ...}ブロック)-これは、Parseを使用している場合に必要です。無効な文字列が解析されます-この場合は不要であるだけでなく、迷惑でコードを複雑にします。 TryParseは、提供したコードサンプルが示しているように、これをすべて回避します。


2) Eric Lippertは有名な StackOverflowの仲間 であり、MicrosoftでC#コンパイラチームの主な開発者として数年間働いていました。

40
Matt
var dateStr = @"2011-03-21 13:26";
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture);

他のフォーマット文字列については、--- link をチェックしてください。

13
Rob

DateTime.Parse()はその文字列フォーマットに対してはうまく動作するはずです。参照:

http://msdn.Microsoft.com/ja-jp/library/1k1skd40.aspx#Y124

それはあなたのためにFormatExceptionを投げていますか?

5
cacois

このようなコードを使用して、人間が読める文字列の値を.NETのDateTimeに入れます。

DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);
4
Zack Peterson

XmlConvert.ToDateStringを使うこともできます

var dateStr = "2011-03-21 13:26";
var parsedDate = XmlConvert.ToDateTime(dateStr, "yyyy-MM-dd hh:mm");

日付の種類を指定することをお勧めします。コードは次のとおりです。

var anotherParsedDate = DateTime.ParseExact(dateStr, "yyyy-MM-dd hh:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

さまざまな解析オプションの詳細 http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html

2
Amir Shenouda

単純明快な答え - >

using System;

namespace DemoApp.App

{
public class TestClassDate
{
    public static DateTime GetDate(string string_date)
    {
        DateTime dateValue;
        if (DateTime.TryParse(string_date, out dateValue))
            Console.WriteLine("Converted '{0}' to {1}.", string_date, dateValue);
        else
            Console.WriteLine("Unable to convert '{0}' to a date.", string_date);
        return dateValue;
    }
    public static void Main()
    {
        string inString = "05/01/2009 06:32:00";
        GetDate(inString);
    }
}
}

/**
 * Output:
 * Converted '05/01/2009 06:32:00' to 5/1/2009 6:32:00 AM.
 * */
2

次のコードを試してください

Month = Date = DateTime.Now.Month.ToString();   
Year = DateTime.Now.Year.ToString(); 
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;
0
Adil Ayoub