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


165

私が持っている日付と時刻を 1つのようにフォーマットされた文字列に:

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

どうすれば解析できSystem.DateTimeますか?

私は次のような機能を使用するDateTime.Parse()か、DateTime.ParseExact()手動で日付の形式を指定できるようにし、可能な場合。


19
では、DateTime.Parseを使用しないのはなぜですか。
オースティンサローネン

8
私は反対投票者の一人でした。これは、元の質問(stackoverflow.com/revisions/…)がDateTime.Parse()の使用を望んでいたが、使用できない理由を述べていなかったためです。これは、特に単純なチェックでcacoisが正しいことが明らかになったので、ナンセンスな質問のように見えました。文字列「2011-03-21 13:26」は、DateTime.Parse()の問題ではありません。最後に、元の質問でParseExact()について言及していません。これを編集に追加するためミッチの答えが出るまで待ちました。
anon

4
コメントに理由を付けずに質問を投票する人々が大好きです。
Hooch 2015

回答:


271

DateTime.Parse()与えられた日付のフォーマットを理解しようとします、そしてそれは通常良い仕事をします。日付が常に特定の形式であることを保証できる場合は、次を使用できますParseExact()

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

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

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

フォーマット文字列を作成するときは必ずカスタムの日付と時間のフォーマット文字列を確認してください 。特に、文字数と大文字と小文字に注意してください(「MM」と「mm」は非常に異なる意味です)。

C#の書式指定文字列のための別の有用なリソースがあるC#で文字列フォーマット


5
修正-常に安全です;)例外を使用してメソッドを呼び出す場合は、可能であれば常に最初に例外条件を確認してください。
Gusdor 2013

3
常にあなたの文化に合格するほうが安全だと思います。「2013年2月1日」が1月2日か2月1日のどちらかと誤解されるよりも、例外を設けたいと思います。
Carra

1
@Carra:ISO8601形式の日付(つまり、yyyy-mm-dd 'は常に正しい方法で解釈されます。それが、ISO8601形式の日付を使用する理由です
Mitch Wheat

正確な解析が役立ちます。ときどき、誤った出力を生成するのではなく、アプリケーションのクラッシュとコンピューターのライトの点灯を優先します。アプリケーションによって異なります。
アレン

ParseExactには柔軟性があるためすばらしいですが、欠点がありますs。変数の日付形式に構文エラーがあると、ParseExactメソッドとParseメソッドが例外をスローすることに注意してください。したがって、TryParseExcactを使用することをお勧めします。以下の私の回答で理由を指摘しました。
Matt

47

後で説明するように、私は常に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)。

?.たとえば、 "Elvis" -operatorのようなエレガントなショートカットを使用することもできます。

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:これは、関数がフォーマットパターンを常に同じ方法で処理するように強制することです(それ以外の場合、たとえば、「。」は、グループセパレータまたは日付セパレータである一方で、英語の小数点として解釈されます。ドイツ人)。カルチャベースのフォーマット文字列を数行前に既にクエリしたので、ここではそれを思い出してください。

更新:( .ToDate()パラメーターなしで)デフォルトで、スレッドの現在のカルチャのすべての一般的な日付/時刻パターンにデフォルト設定されるようになりました。とを一緒に使用する必要があることに
注意してください。これは、ではを使用できないためです。ではC#バージョン7あなたは単純化でき、次のようにビットの機能を:resultdtTryParseExactDateTime?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 dtout var dtそれを好む場合の代わりに書くことも許可されます)。

paramsキーワードを使用してコードをさらに簡略化しました。これで、2 番目のオーバーロードメソッドは必要なくなりました。


使用例

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はstrictを指定できるDateTimeStylesため、適切な日付/時刻文字列が渡されたかどうかを正確に把握できます。


その他の使用例

オーバーロードされた関数により、ここに示すように、日付の解析/変換に使用される有効なフォーマットの配列を渡すことができます(これを直接サポートします)。例: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標準形式を使用しようとします"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をあなたがするので、この拡張メソッドで例外処理を避けるため、あなたがすることができます- 例外に関するエリックリペットの記事で読んで:私はそのトピックについて彼の言葉を引用、あなたはむしろ解析よりTryParseを使用すべき理由)2

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

それは可能ですがTryParseTryParseExactどちらもまだ快適に使用できません。これらは、初期化されていない変数をoutnullにしてはいけないパラメーターとして使用することを強制し、変換中はブール戻り値を評価する必要があります。ifステートメントをすぐに使用するには、または戻り値を追加のブール変数に格納して、後でチェックできるようにする必要があります。また、変換が成功したかどうかを知らずに、ターゲット変数を使用することはできません。

ほとんどの場合、変換が成功したかどうか(そしてもちろん成功した場合の値)を知りたいだけなので、すべての情報を保持するnull許容のターゲット変数が望ましいでしょう。 1つの場所に格納されているだけです。これは一貫性があり、使いやすく、エラーが発生しにくくなっています。

私が書いた拡張メソッドは、まさにそれを実行します(これを使用しない場合に毎回記述する必要があるコードの種類も示します)。

私の利点.ToDate(strDateFormat)は、それがシンプルでクリーンに見えるDateTime.Parseことです- 元のものがそうであったように- シンプルですが、変換が成功したかどうかをチェックする機能があり、例外をスローしません。


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


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


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

他のフォーマット文字列については、このリンクをチェックしてください!



4

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

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

2

単純明快な答え->

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.
 * */

素敵な@Shivam Bharadwaj、私は同じようにした
Muhammad Irfan

2

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


0

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

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

こんにちは、ようこそ、質問に答えるときに説明を提供してください。コードを投稿するだけではお勧めできません
Ali
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.