私が持っている日付と時刻を 1つのようにフォーマットされた文字列に:
"2011-03-21 13:26" //year-month-day hour:minute
どうすれば解析できSystem.DateTime
ますか?
私は次のような機能を使用するDateTime.Parse()
か、DateTime.ParseExact()
手動で日付の形式を指定できるようにし、可能な場合。
私が持っている日付と時刻を 1つのようにフォーマットされた文字列に:
"2011-03-21 13:26" //year-month-day hour:minute
どうすれば解析できSystem.DateTime
ますか?
私は次のような機能を使用するDateTime.Parse()
か、DateTime.ParseExact()
手動で日付の形式を指定できるようにし、可能な場合。
回答:
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#で文字列フォーマット
s
。変数の日付形式に構文エラーがあると、ParseExactメソッドとParseメソッドが例外をスローすることに注意してください。したがって、TryParseExcactを使用することをお勧めします。以下の私の回答で理由を指摘しました。
後で説明するように、私は常にTryParse
およびTryParseExact
メソッドを優先します。使用するのが少しかさばるので、構文解析をはるかに簡単にする拡張メソッドを作成しました。
var dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");
などとは異なりParse
、ParseExact
例外はスローされず、
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()拡張メソッド
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あなたは単純化でき、次のようにビットの機能を:result
dt
TryParseExact
DateTime?
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 番目のオーバーロードメソッドは必要なくなりました。
使用例
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を実装しまし たが、これは正しいことを行います。
それは可能ですがTryParse
、TryParseExact
どちらもまだ快適に使用できません。これらは、初期化されていない変数をout
nullにしてはいけないパラメーターとして使用することを強制し、変換中はブール戻り値を評価する必要があります。if
ステートメントをすぐに使用するには、または戻り値を追加のブール変数に格納して、後でチェックできるようにする必要があります。また、変換が成功したかどうかを知らずに、ターゲット変数を使用することはできません。
ほとんどの場合、変換が成功したかどうか(そしてもちろん成功した場合の値)を知りたいだけなので、すべての情報を保持するnull許容のターゲット変数が望ましいでしょう。 1つの場所に格納されているだけです。これは一貫性があり、使いやすく、エラーが発生しにくくなっています。
私が書いた拡張メソッドは、まさにそれを実行します(これを使用しない場合に毎回記述する必要があるコードの種類も示します)。
私の利点.ToDate(strDateFormat)
は、それがシンプルでクリーンに見えるDateTime.Parse
ことです- 元のものがそうであったように- シンプルですが、変換が成功したかどうかをチェックする機能があり、例外をスローしません。
1)ここで意味するのは、無効な文字列が解析されると例外がスローされるため、Parseを使用しているときに必要な例外処理(つまりtry { ... } catch(Exception ex) { ...}
ブロック)です。この場合、不必要なだけでなく、煩わしいコードを複雑にします。私が提供したコードサンプルが示すように、TryParseはこれをすべて回避します。
2) Eric Lippertは有名なStackOverflowフェローで、MicrosoftでC#コンパイラチームの主要開発者として数年間働いていました。
DateTime.Parse()は、その文字列フォーマットで正常に機能するはずです。参照:
http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240
それはあなたのためにFormatExceptionをスローしていますか?
次のようなコードを使用して、人間が読める文字列の値を.NET DateTimeに入れます。
DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);
単純明快な答え->
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.
* */
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