英語で読む

次の方法で共有


System.DateTime 構造体

この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。

重要

日本暦の年号は天皇の治世に基づいているため、変化することが期待されます。 たとえば、2019 年 5 月 1 日は、 JapaneseCalendarJapaneseLunisolarCalendarのレイワ時代の始まりを迎えています。 このような時代の変化は、これらのカレンダーを使用するすべてのアプリケーションに影響します。 詳細およびアプリケーションが影響を受けるかどうかを判断するには、「 .NET の日本語カレンダーでの新しい時代 (年号) の処理」を参照してください。 Windows システムでアプリケーションをテストし、時代 (年号) の変更に対する準備を行う方法については、「 日本の時代 (年号) に合わせてアプリケーションを準備する」を参照してください。 複数の時代 (年号) を含むカレンダーをサポートする .NET の機能と、複数の時代 (年号) をサポートするカレンダーを使用する場合のベスト プラクティスについては、「 年号の使用」を参照してください。

概要

DateTime値の型は、グレゴリオ暦で紀元前1年1月1日午前0時0分0秒から9999年12月31日午後11時59分59秒までの日付と時刻を表します。

時間値は、ティックと呼ばれる 100 ナノ秒単位で測定されます。 特定の日付は、GregorianCalendar カレンダーにおいて西暦 0001 年 1 月 1 日午前 0 時からの経過時間をティックで表した数値です。 この数値には、うるう秒によって追加されるティックは含まれていません。 たとえば、タイマー刻み値 31241376000000000L は、0100 年 1 月 1 日 (金曜日) 深夜 12:00:00 を表します。 DateTime値は、常に明示的または既定のカレンダーのコンテキストで表されます。

注意

分や秒などの他の時間間隔に変換するティック値を使用する場合は、 TimeSpan.TicksPerDayTimeSpan.TicksPerHourTimeSpan.TicksPerMinuteTimeSpan.TicksPerSecond、または TimeSpan.TicksPerMillisecond 定数を使用して変換を実行する必要があります。 たとえば、指定したティック数で表される秒数をDateTime値のSecondコンポーネントに追加するには、式dateValue.Second + nTicks/Timespan.TicksPerSecondを使用します。

この記事の一連の例全体のソースは、 Visual BasicF#、または C# で確認できます。

注意

特定のタイム ゾーンで日付と時刻の値を操作するための DateTime 構造の代わりに、 DateTimeOffset 構造体があります。 DateTimeOffset構造体は、日付と時刻の情報をプライベート DateTime フィールドに格納し、その日付と時刻がプライベート Int16 フィールドの UTC と異なる分数を格納します。 これにより、 DateTimeOffset 値は特定のタイム ゾーンの時刻を反映できますが、 DateTime 値は UTC とローカル タイム ゾーンの時刻のみを明確に反映できます。 日付と時刻の値を操作するときに DateTime 構造体または DateTimeOffset 構造体を使用するタイミングについては、「 DateTime、DateTimeOffset、TimeSpan、TimeZoneInfo の選択」を参照してください。

注意

この記事のいくつかの C# の例は、Try.NET インライン コード ランナーとプレイグラウンドで実行 されます[実行] ボタンを選択すると、対話型ウィンドウで例が実行されます。 コードを実行したら、コードを変更し、[実行] をもう一度選択して変更後のコードを実行できます。 変更後のコードが対話型ウィンドウで実行されるか、コンパイルできなかった場合、対話型ウィンドウにすべての C# コンパイラ エラー メッセージが表示されます。

Try.NET インライン コード ランナーとプレイグラウンドの ローカル タイム ゾーン は、協定世界時 (UTC) です。 これは、DateTimeDateTimeOffset、および TimeZoneInfo 型とそのメンバーを示す例の動作と出力に影響する可能性があります。

この記事には、 DateTime 型を使用するいくつかの例が含まれています。

初期化の例

DateTimeオブジェクトを文字列の例として書式設定する

DateTime オブジェクトの例として文字列を解析する

DateTime 解決策の例

カルチャとカレンダーの例

永続化の例

DateTime オブジェクトを初期化する

初期値は、さまざまな方法で新しい DateTime 値に割り当てることができます。

  • コンストラクターを呼び出します。値の引数を指定するか、暗黙的なパラメーターなしのコンストラクターを使用します。
  • プロパティまたはメソッドの戻り値に DateTime を割り当てる。
  • 文字列表現から DateTime 値を解析する。
  • Visual Basic 固有の言語機能を使用して DateTimeをインスタンス化する。

次のコード スニペットは、それぞれの例を示しています。

コンストラクターを呼び出す

日付と時刻の値 (年、月、日、ティック数など) の要素を指定する、 DateTime コンストラクターのいずれかのオーバーロードを呼び出します。 次のコードでは、年、月、日、時、分、秒を指定する DateTime コンストラクターを使用して、特定の日付を作成します。

var date1 = new DateTime(2008, 5, 1, 8, 30, 52);
Console.WriteLine(date1);

DateTimeを既定値に初期化する場合は、DateTime構造体の暗黙的なパラメーターなしのコンストラクターを呼び出します。 (値型の暗黙的なパラメーターなしのコンストラクターの詳細については、「 型」を参照してください)。一部のコンパイラでは、値を明示的に割り当てずに DateTime 値を宣言することもできます。 明示的な初期化なしで値を作成すると、既定値にもなります。 次の例は、C# と Visual Basic の DateTime 暗黙的なパラメーターなしのコンストラクターと、Visual Basic での割り当てなしの DateTime 宣言を示しています。

var dat1 = new DateTime();
// The following method call displays 1/1/0001 12:00:00 AM.
Console.WriteLine(dat1.ToString(System.Globalization.CultureInfo.InvariantCulture));
// The following method call displays True.
Console.WriteLine(dat1.Equals(DateTime.MinValue));

計算値を割り当てる

DateTime オブジェクトには、プロパティまたはメソッドによって返される日付と時刻の値を割り当てることができます。 次の例では、現在の日付と時刻、現在の世界協定時刻 (UTC) の日付と時刻、および現在の日付を 3 つの新しい DateTime 変数に割り当てます。

DateTime date1 = DateTime.Now;
DateTime date2 = DateTime.UtcNow;
DateTime date3 = DateTime.Today;

DateTime を表す文字列を解析する

ParseParseExactTryParse、およびTryParseExactのメソッドはすべて、文字列を等価の日付と時刻の値に変換します。 次の例では、 Parse メソッドと ParseExact メソッドを使用して文字列を解析し、 DateTime 値に変換します。 2 番目の形式では、文字列形式で日付と時刻を表す ISO 8601 標準でサポートされているフォームを使用します。 この標準表現は、多くの場合、Web サービスの日付情報を転送するために使用されます。

var dateString = "5/1/2008 8:30:52 AM";
DateTime date1 = DateTime.Parse(dateString,
                          System.Globalization.CultureInfo.InvariantCulture);
var iso8601String = "20080501T08:30:52Z";
DateTime dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
                                System.Globalization.CultureInfo.InvariantCulture);

TryParseメソッドとTryParseExactメソッドは、文字列がDateTime値の有効な表現であるかどうかを示し、有効な場合は変換を実行します。

Visual Basic の言語固有の構文

次の Visual Basic ステートメントは、新しい DateTime 値を初期化します。

Dim date1 As Date = #5/1/2008 8:30:52AM#

DateTime 値とその文字列表現

内部的には、すべての DateTime 値は、0001 年 1 月 1 日の午前 12 時 00 分から経過したティック数 (100 ナノ秒間隔の数) として表されます。 実際の DateTime 値は、表示時にその値が表示される方法とは無関係です。 DateTime値の外観は、値を文字列形式に変換する書式設定操作の結果です。

日付と時刻の値の外観は、カルチャ、国際標準、アプリケーション要件、個人の好みに応じて異なります。 DateTime構造体は、ToStringのオーバーロードによって日付と時刻の値を柔軟に書式設定できます。 既定の DateTime.ToString() メソッドは、現在のカルチャの短い日付と長い時間パターンを使用して、日付と時刻の値の文字列形式を返します。 次の例では、既定の DateTime.ToString() メソッドを使用します。 現在のカルチャの短い日付と長い時間パターンを使用して、日付と時刻が表示されます。 en-US カルチャは、この例が実行されたコンピューター上の現在のカルチャです。

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString());
// For en-US culture, displays 3/1/2008 7:00:00 AM

サーバーがクライアントとは異なるカルチャにある可能性がある Web シナリオをサポートするために、特定のカルチャの日付の書式設定が必要になる場合があります。 DateTime.ToString(IFormatProvider) メソッドを使用してカルチャを指定し、特定のカルチャで短い日付と長い時間の表現を作成します。 次の例では、 DateTime.ToString(IFormatProvider) メソッドを使用して、fr-FR カルチャの短い日付と長い時間パターンを使用して日付と時刻を表示します。

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString(System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays 01/03/2008 07:00:00

他のアプリケーションでは、日付の異なる文字列表現が必要になる場合があります。 DateTime.ToString(String) メソッドは、現在のカルチャの書式設定規則を使用して、標準書式指定子またはカスタム書式指定子によって定義された文字列形式を返します。 次の例では、 DateTime.ToString(String) メソッドを使用して、en-US カルチャの完全な日付と時刻のパターン (この例が実行されたコンピューター上の現在のカルチャ) を表示します。

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString("F"));
// Displays Saturday, March 01, 2008 7:00:00 AM

最後に、 DateTime.ToString(String, IFormatProvider) メソッドを使用してカルチャと形式の両方を指定できます。 次の例では、 DateTime.ToString(String, IFormatProvider) メソッドを使用して、fr-FR カルチャの完全な日付と時刻のパターンを表示します。

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString("F", new System.Globalization.CultureInfo("fr-FR")));
// Displays samedi 1 mars 2008 07:00:00

DateTime.ToString(String)オーバーロードは、カスタム書式指定文字列と共に使用して、他の形式を指定することもできます。 次の例は、Web サービスでよく使用される ISO 8601 標準形式を使用して文字列を書式設定する方法を示しています。 Iso 8601 形式には、対応する標準書式指定文字列がありません。

var date1 = new DateTime(2008, 3, 1, 7, 0, 0, DateTimeKind.Utc);
Console.WriteLine(date1.ToString("yyyy-MM-ddTHH:mm:sszzz", System.Globalization.CultureInfo.InvariantCulture));
// Displays 2008-03-01T07:00:00+00:00

DateTime値の書式設定の詳細については、「標準の日付と時刻の書式指定文字列」およびカスタム日時書式指定文字列」を参照してください。

文字列から DateTime 値を解析する

解析により、日付と時刻の文字列形式が DateTime 値に変換されます。 通常、日付と時刻の文字列には、アプリケーションで次の 2 つの使用法があります。

  • 日付と時刻にはさまざまな形式があり、現在のカルチャまたは特定のカルチャの規則が反映されます。 たとえば、アプリケーションを使用すると、現在のカルチャが en-US されているユーザーは、日付値を "2013 年 12 月 15 日" または "2013 年 12 月 15 日" として入力できます。 現在のカルチャが en-gb されているユーザーは、日付値を "15/12/2013" または "2013 年 12 月 15 日" として入力できます。

  • 日付と時刻は、定義済みの形式で表されます。 たとえば、アプリケーションは、アプリが実行されているカルチャとは別に、日付を "20130103" としてシリアル化します。 アプリケーションでは、日付を現在のカルチャの短い日付形式で入力する必要がある場合があります。

Parseメソッドまたは TryParse メソッドを使用して、カルチャで使用される一般的な日付と時刻の形式の 1 つからDateTime値に文字列を変換します。 次の例は、 TryParse を使用して、カルチャ固有の異なる形式の日付文字列を DateTime 値に変換する方法を示しています。 現在のカルチャを英語 (英国) に変更し、 GetDateTimeFormats() メソッドを呼び出して、日付と時刻の文字列の配列を生成します。 次に、配列内の各要素を TryParse メソッドに渡します。 この例の出力は、解析メソッドがカルチャ固有の各日付と時刻の文字列を正常に変換できたことを示しています。

System.Threading.Thread.CurrentThread.CurrentCulture =
    System.Globalization.CultureInfo.CreateSpecificCulture("en-GB");

var date1 = new DateTime(2013, 6, 1, 12, 32, 30);
var badFormats = new List<String>();

Console.WriteLine($"{"Date String",-37} {"Date",-19}\n");
foreach (var dateString in date1.GetDateTimeFormats())
{
    DateTime parsedDate;
    if (DateTime.TryParse(dateString, out parsedDate))
        Console.WriteLine($"{dateString,-37} {DateTime.Parse(dateString),-19}");
    else
        badFormats.Add(dateString);
}

// Display strings that could not be parsed.
if (badFormats.Count > 0)
{
    Console.WriteLine("\nStrings that could not be parsed: ");
    foreach (var badFormat in badFormats)
        Console.WriteLine($"   {badFormat}");
}
// Press "Run" to see the output.

ParseExactメソッドとTryParseExactメソッドを使用して、特定の形式または書式に一致する必要がある文字列をDateTime値に変換します。 解析メソッドのパラメーターとして、1 つ以上の日付と時刻の書式指定文字列を指定します。 次の例では、TryParseExact(String, String[], IFormatProvider, DateTimeStyles, DateTime) メソッドを使用して、"yyyyMMdd" 形式または "HHmmss" 形式の文字列を DateTime 値に変換しています。

string[] formats = { "yyyyMMdd", "HHmmss" };
string[] dateStrings = { "20130816", "20131608", "  20130816   ",
                   "115216", "521116", "  115216  " };
DateTime parsedDate;

foreach (var dateString in dateStrings)
{
    if (DateTime.TryParseExact(dateString, formats, null,
                               System.Globalization.DateTimeStyles.AllowWhiteSpaces |
                               System.Globalization.DateTimeStyles.AdjustToUniversal,
                               out parsedDate))
        Console.WriteLine($"{dateString} --> {parsedDate:g}");
    else
        Console.WriteLine($"Cannot convert {dateString}");
}
// The example displays the following output:
//       20130816 --> 8/16/2013 12:00 AM
//       Cannot convert 20131608
//         20130816    --> 8/16/2013 12:00 AM
//       115216 --> 4/22/2013 11:52 AM
//       Cannot convert 521116
//         115216   --> 4/22/2013 11:52 AM

ParseExactの一般的な用途の 1 つは、通常は ISO 8601 標準形式で Web サービスから文字列形式を変換することです。 次のコードは、使用する正しい書式指定文字列を示しています。

var iso8601String = "20080501T08:30:52Z";
DateTime dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
    System.Globalization.CultureInfo.InvariantCulture);
Console.WriteLine($"{iso8601String} --> {dateISO8602:g}");

文字列を解析できない場合、 Parse メソッドと ParseExact メソッドは例外をスローします。 TryParseメソッドとTryParseExact メソッドは、変換が成功したか失敗したかを示すBoolean値を返します。 パフォーマンスが重要なシナリオでは、 TryParse または TryParseExact メソッドを使用する必要があります。 日付と時刻の文字列の解析操作は、エラー率が高くなる傾向があり、例外処理はコストがかかります。 文字列がユーザーによって入力された場合、または不明なソースから取得された場合は、これらのメソッドを使用します。

日付と時刻の値の解析の詳細については、「 日付と時刻の文字列の解析」を参照してください。

DateTime 値

DateTime型の時刻値の説明は、多くの場合、協定世界時 (UTC) 標準を使用して表されます。 協定世界時はグリニッジ標準時 (GMT) の国際的に認められた名前です。 協定世界時は、経度 0 度 (UTC の起点) で測定された時刻です。 夏時間は UTC には適用されません。

ローカル時刻は、特定のタイム ゾーンを基準としています。 タイム ゾーンはタイム ゾーン オフセットに関連付けられます。 タイム ゾーン オフセットは、UTC の起点から時間単位で測定されたタイム ゾーンの変位です。 さらに、ローカル時刻は必要に応じて夏時間の影響を受け、時間間隔の調整を加算または減算します。 現地時刻は、UTC にタイム ゾーン オフセットを追加し、必要に応じて夏時間に合わせて調整することによって計算されます。 UTC 起点のタイム ゾーン オフセットは 0 です。

UTC 時刻は、計算、比較、および日付と時刻のファイルへの格納に適しています。 ローカル時刻は、デスクトップ アプリケーションのユーザー インターフェイスでの表示に適しています。 タイム ゾーン対応アプリケーション (多くの Web アプリケーションなど) も、他の多くのタイム ゾーンで動作する必要があります。

DateTime オブジェクトのKind プロパティがDateTimeKind.Unspecified場合、表される時刻が現地時刻、UTC 時刻、またはその他のタイム ゾーン内の時刻のいずれであるかは指定されません。

DateTime の解決

注意

DateTime値に対して日付と時刻の算術演算を実行して経過時間を測定する代わりに、Stopwatch クラスを使用できます。

Ticks プロパティは、日付と時刻の値を 1000 万分の 1 秒の単位で表します。 Millisecond プロパティは、日付と時刻の値で秒の 1000 分の 1 を返します。 DateTime.Now プロパティを繰り返し呼び出して経過時間を測定することは、システム クロックによって異なります。 Windows 7 および Windows 8 システムのシステム クロックの解像度は約 15 ミリ秒です。 この解像度は、100 ミリ秒未満の短い時間間隔に影響します。

次の例は、現在の日付と時刻の値がシステム クロックの解像度に依存する方法を示しています。 この例では、外側のループは 20 回繰り返され、内部ループは外側のループを遅延させる役割を果たします。 外側のループ カウンターの値が 10 の場合、 Thread.Sleep メソッドを呼び出すと 5 ミリ秒の遅延が発生します。 次の例は、Thread.Sleepの呼び出し後にのみ、DateTime.Now.Milliseconds プロパティによって返されるミリ秒数を示しています。

string output = "";
for (int ctr = 0; ctr <= 20; ctr++)
{
    output += String.Format($"{DateTime.Now.Millisecond}\n");
    // Introduce a delay loop.
    for (int delay = 0; delay <= 1000; delay++)
    { }

    if (ctr == 10)
    {
        output += "Thread.Sleep called...\n";
        System.Threading.Thread.Sleep(5);
    }
}
Console.WriteLine(output);
// Press "Run" to see the output.

DateTime 操作

AddSubtractなど、DateTime構造体を使用した計算では、構造体の値は変更されません。 代わりに、計算結果の値を持つ新しい DateTime 構造体が返されます。

タイム ゾーン間の変換操作 (UTC とローカル時刻の間、またはタイム ゾーンと別のタイム ゾーン間など) では夏時間が考慮されますが、算術演算と比較操作では考慮されません。

DateTime構造体自体では、あるタイム ゾーンから別のタイム ゾーンへの変換のサポートが制限されています。 ToLocalTimeメソッドを使用して UTC を現地時刻に変換することも、ToUniversalTime メソッドを使用して現地時刻から UTC に変換することもできます。 ただし、 TimeZoneInfo クラスでは、タイム ゾーン変換メソッドの完全なセットを使用できます。 これらのメソッドを使用して、世界のいずれかのタイム ゾーンの時刻を他のタイム ゾーンの時刻に変換します。

DateTimeオブジェクトの計算と比較は、オブジェクトが同じタイム ゾーン内の時刻を表す場合にのみ意味があります。 TimeZoneInfo オブジェクトを使用して、DateTime値のタイム ゾーンを表すことができますが、2 つのオブジェクトは疎結合されています。 DateTime オブジェクトには、その日付と時刻の値のタイム ゾーンを表すオブジェクトを返すプロパティがありません。 Kind プロパティは、DateTimeが UTC、現地時刻、または指定されていないかどうかを示します。 タイム ゾーン対応アプリケーションでは、外部メカニズムに依存して、 DateTime オブジェクトが作成されたタイム ゾーンを特定する必要があります。 DateTime値と、DateTime値のタイム ゾーンを表すTimeZoneInfo オブジェクトの両方をラップする構造体を使用できます。 計算での UTC の使用と DateTime 値との比較の詳細については、「 日付と時刻を使用した算術演算の実行」を参照してください。

DateTime メンバーは、グレゴリオ暦を暗黙的に使用してその操作を実行します。 例外は、カレンダーを暗黙的に指定するメソッドです。 これには、カレンダーを指定するコンストラクターや、 IFormatProviderから派生したパラメーターを持つメソッド ( System.Globalization.DateTimeFormatInfoなど) が含まれます。

DateTime型のメンバーによる操作では、閏年や 1 か月の日数などの詳細が考慮されます。

DateTime の値とカレンダー

.NET クラス ライブラリには、 Calendar クラスから派生したカレンダー クラスが多数含まれています。 これらは次のとおりです。

重要

日本暦の年号は天皇の治世に基づいているため、変化することが期待されます。 たとえば、2019 年 5 月 1 日は、 JapaneseCalendarJapaneseLunisolarCalendarのレイワ時代の始まりを迎えています。 このような時代の変化は、これらのカレンダーを使用するすべてのアプリケーションに影響します。 詳細およびアプリケーションが影響を受けるかどうかを判断するには、「 .NET の日本語カレンダーでの新しい時代 (年号) の処理」を参照してください。 Windows システムでアプリケーションをテストし、時代 (年号) の変更に対する準備を行う方法については、「 日本の時代 (年号) に合わせてアプリケーションを準備する」を参照してください。 複数の時代 (年号) を含むカレンダーをサポートする .NET の機能と、複数の時代 (年号) をサポートするカレンダーを使用する場合のベスト プラクティスについては、「 年号の使用」を参照してください。

各カルチャでは、読み取り専用の CultureInfo.Calendar プロパティで定義された既定の予定表が使用されます。 各カルチャでは、読み取り専用の CultureInfo.OptionalCalendars プロパティによって定義された 1 つ以上の予定表をサポートできます。 現在、特定の CultureInfo オブジェクトによって使用されているカレンダーは、その DateTimeFormatInfo.Calendar プロパティによって定義されます。 CultureInfo.OptionalCalendars配列にあるカレンダーのいずれかである必要があります。

カルチャの現在のカレンダーは、そのカルチャのすべての書式設定操作で使用されます。 たとえば、タイ仏教文化の既定の暦は、 ThaiBuddhistCalendar クラスで表されるタイ仏教時代の暦です。 タイ仏教の文化を表す CultureInfo オブジェクトが日付と時刻の書式設定操作で使用されている場合、タイ仏教時代の暦が既定で使用されます。 グレゴリオ暦は、次の例に示すように、カルチャの DateTimeFormatInfo.Calendar プロパティが変更された場合にのみ使用されます。

var thTH = new System.Globalization.CultureInfo("th-TH");
var value = new DateTime(2016, 5, 28);

Console.WriteLine(value.ToString(thTH));

thTH.DateTimeFormat.Calendar = new System.Globalization.GregorianCalendar();
Console.WriteLine(value.ToString(thTH));
// The example displays the following output:
//       28/5/2559 0:00:00
//       28/5/2016 0:00:00

次の例に示すように、カルチャの現在のカレンダーは、そのカルチャのすべての解析操作でも使用されます。

var thTH = new System.Globalization.CultureInfo("th-TH");
var value = DateTime.Parse("28/05/2559", thTH);
Console.WriteLine(value.ToString(thTH));

thTH.DateTimeFormat.Calendar = new System.Globalization.GregorianCalendar();
Console.WriteLine(value.ToString(thTH));
// The example displays the following output:
//       28/5/2559 0:00:00
//       28/5/2016 0:00:00

calendar パラメーターを含む DateTime コンストラクターを呼び出し、そのカレンダーを表すCalendar オブジェクトを渡すことによって、特定のカレンダーの日付と時刻の要素 (年、月、日の数) を使用してDateTime値をインスタンス化します。 次の例では、 ThaiBuddhistCalendar カレンダーの日付と時刻の要素を使用します。

var thTH = new System.Globalization.CultureInfo("th-TH");
var dat = new DateTime(2559, 5, 28, thTH.DateTimeFormat.Calendar);
Console.WriteLine($"Thai Buddhist era date: {dat.ToString("d", thTH)}");
Console.WriteLine($"Gregorian date:   {dat:d}");
// The example displays the following output:
//       Thai Buddhist Era Date:  28/5/2559
//       Gregorian Date:     28/05/2016

DateTimecalendarパラメーターを含まないコンストラクターは、日付と時刻の要素がグレゴリオ暦の単位として表されることを前提としています。

その他のすべての DateTime プロパティとメソッドは、グレゴリオ暦を使用します。 たとえば、 DateTime.Year プロパティはグレゴリオ暦の年を返し、 DateTime.IsLeapYear(Int32) メソッドは、 year パラメーターがグレゴリオ暦の年であると仮定します。 グレゴリオ暦を使用する各 DateTime メンバーには、特定のカレンダーを使用する Calendar クラスの対応するメンバーがあります。 たとえば、 Calendar.GetYear メソッドは特定のカレンダーの年を返し、 Calendar.IsLeapYear メソッドは year パラメーターを特定のカレンダーの年番号として解釈します。 次の例では、 DateTime と、 ThaiBuddhistCalendar クラスの対応するメンバーの両方を使用します。

var thTH = new System.Globalization.CultureInfo("th-TH");
var cal = thTH.DateTimeFormat.Calendar;
var dat = new DateTime(2559, 5, 28, cal);
Console.WriteLine("Using the Thai Buddhist Era calendar:");
Console.WriteLine($"Date: {dat.ToString("d", thTH)}");
Console.WriteLine($"Year: {cal.GetYear(dat)}");
Console.WriteLine($"Leap year: {cal.IsLeapYear(cal.GetYear(dat))}\n");

Console.WriteLine("Using the Gregorian calendar:");
Console.WriteLine($"Date: {dat:d}");
Console.WriteLine($"Year: {dat.Year}");
Console.WriteLine($"Leap year: {DateTime.IsLeapYear(dat.Year)}");
// The example displays the following output:
//       Using the Thai Buddhist Era calendar
//       Date :   28/5/2559
//       Year: 2559
//       Leap year :   True
//
//       Using the Gregorian calendar
//       Date :   28/05/2016
//       Year: 2016
//       Leap year :   True

DateTime構造体には、グレゴリオ暦の曜日を返すDayOfWeekプロパティが含まれています。 年の週番号を取得できるメンバーは含まれません。 年の週を取得するには、個々のカレンダーの Calendar.GetWeekOfYear メソッドを呼び出します。 具体的な例を次に示します。

var thTH = new System.Globalization.CultureInfo("th-TH");
var thCalendar = thTH.DateTimeFormat.Calendar;
var dat = new DateTime(1395, 8, 18, thCalendar);
Console.WriteLine("Using the Thai Buddhist Era calendar:");
Console.WriteLine($"Date: {dat.ToString("d", thTH)}");
Console.WriteLine($"Day of Week: {thCalendar.GetDayOfWeek(dat)}");
Console.WriteLine($"Week of year: {thCalendar.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}\n");

var greg = new System.Globalization.GregorianCalendar();
Console.WriteLine("Using the Gregorian calendar:");
Console.WriteLine($"Date: {dat:d}");
Console.WriteLine($"Day of Week: {dat.DayOfWeek}");
Console.WriteLine($"Week of year: {greg.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay,DayOfWeek.Sunday)}");
// The example displays the following output:
//       Using the Thai Buddhist Era calendar
//       Date :  18/8/1395
//       Day of Week: Sunday
//       Week of year: 34
//
//       Using the Gregorian calendar
//       Date :  18/08/0852
//       Day of Week: Sunday
//       Week of year: 34

日付とカレンダーの詳細については、「 カレンダーの操作」を参照してください。

DateTime 値を保持する

DateTime値は、次の方法で保持できます。

選択した手法に関係なく、 DateTime 値を復元するルーチンがデータを失ったり、例外をスローしたりしないようにする必要があります。 DateTime 値は往復する必要があります。 つまり、元の値と復元された値は同じである必要があります。 また、元の DateTime 値が 1 回の時間を表す場合は、復元された時刻と同じ瞬間を識別する必要があります。

値を文字列として保持する

文字列として永続化 DateTime 値を正常に復元するには、次の規則に従います。

  • 文字列を永続化したときと同じように、カルチャ固有の書式を復元する場合と同じ前提を設定します。 現在のカルチャが保存されたシステムのカルチャと異なるシステムで文字列を復元できるようにするには、 ToString オーバーロードを呼び出して、インバリアント カルチャの規則を使用して文字列を保存します。 インバリアント カルチャの規則を使用して文字列を復元するには、 Parse(String, IFormatProvider, DateTimeStyles) または TryParse(String, IFormatProvider, DateTimeStyles, DateTime) オーバーロードを呼び出します。 現在のカルチャの規則を使用する ToString()Parse(String)、または TryParse(String, DateTime) オーバーロードは使用しないでください。

  • 日付が 1 つの時刻の瞬間を表す場合は、別のタイム ゾーンであっても、復元された時刻と同じ瞬間を表すようにします。 DateTime値を保存する前に協定世界時 (UTC) に変換するか、DateTimeOffsetを使用します。

文字列として DateTime 値を永続化するときに発生する最も一般的なエラーは、既定または現在のカルチャの書式設定規則に依存することです。 文字列を保存および復元するときに、現在のカルチャが異なる場合に問題が発生します。 次の例は、これらの問題を示しています。 現在のカルチャの書式設定規則を使用して 5 つの日付を保存します。この場合は英語 (米国) です。 別のカルチャの書式設定規則を使用して日付を復元します。この場合は英語 (英国) です。 2 つのカルチャの書式設定規則が異なるため、2 つの日付を復元することはできません。残りの 3 つの日付は正しく解釈されません。 また、元の日付と時刻の値が 1 つの時点を表している場合、タイム ゾーン情報が失われるため、復元された時刻は正しくありません。

public static void PersistAsLocalStrings()
{
    SaveLocalDatesAsString();
    RestoreLocalDatesFromString();
}

private static void SaveLocalDatesAsString()
{
    DateTime[] dates = { new DateTime(2014, 6, 14, 6, 32, 0),
                   new DateTime(2014, 7, 10, 23, 49, 0),
                   new DateTime(2015, 1, 10, 1, 16, 0),
                   new DateTime(2014, 12, 20, 21, 45, 0),
                   new DateTime(2014, 6, 2, 15, 14, 0) };
    string? output = null;

    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    for (int ctr = 0; ctr < dates.Length; ctr++)
    {
        Console.WriteLine(dates[ctr].ToString("f"));
        output += dates[ctr].ToString() + (ctr != dates.Length - 1 ? "|" : "");
    }
    var sw = new StreamWriter(filenameTxt);
    sw.Write(output);
    sw.Close();
    Console.WriteLine("Saved dates...");
}

private static void RestoreLocalDatesFromString()
{
    TimeZoneInfo.ClearCachedData();
    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
    StreamReader sr = new StreamReader(filenameTxt);
    string[] inputValues = sr.ReadToEnd().Split(new char[] { '|' },
                                                StringSplitOptions.RemoveEmptyEntries);
    sr.Close();
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    foreach (var inputValue in inputValues)
    {
        DateTime dateValue;
        if (DateTime.TryParse(inputValue, out dateValue))
        {
            Console.WriteLine($"'{inputValue}' --> {dateValue:f}");
        }
        else
        {
            Console.WriteLine($"Cannot parse '{inputValue}'");
        }
    }
    Console.WriteLine("Restored dates...");
}
// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       Cannot parse //6/14/2014 6:32:00 AM//
//       //7/10/2014 11:49:00 PM// --> 07 October 2014 23:49
//       //1/10/2015 1:16:00 AM// --> 01 October 2015 01:16
//       Cannot parse //12/20/2014 9:45:00 PM//
//       //6/2/2014 3:14:00 PM// --> 06 February 2014 15:14
//       Restored dates...

DateTimeを円滑にラウンドトリップするためには、次の手順に従ってください。

  1. 値が 1 つの時刻の瞬間を表す場合は、 ToUniversalTime メソッドを呼び出して、ローカル時刻から UTC に変換します。
  2. ToString(String, IFormatProvider)またはString.Format(IFormatProvider, String, Object[])オーバーロードを呼び出して、日付を文字列形式に変換します。 provider引数としてCultureInfo.InvariantCultureを指定して、インバリアント カルチャの書式設定規則を使用します。 "O" または "R" 標準書式指定文字列を使用して値をラウンドトリップすることを指定します。

永続化された DateTime 値をデータ損失なしで復元するには、次の手順に従います。

  1. ParseExactまたはTryParseExactオーバーロードを呼び出して、データを解析します。 provider引数としてCultureInfo.InvariantCultureを指定し、変換時にformat引数に使用したのと同じ標準書式指定文字列を使用します。 styles引数にDateTimeStyles.RoundtripKind値を含めます。
  2. DateTime値が 1 つの時点を表す場合は、ToLocalTime メソッドを呼び出して、解析された日付を UTC から現地時刻に変換します。

次の例では、インバリアント カルチャと "O" 標準書式指定文字列を使用して、保存および復元された DateTime 値が、ソース システムとターゲット システムのシステム、カルチャ、タイム ゾーンに関係なく、同じ時点を表すようにします。

public static void PersistAsInvariantStrings()
{
    SaveDatesAsInvariantStrings();
    RestoreDatesAsInvariantStrings();
}

private static void SaveDatesAsInvariantStrings()
{
    DateTime[] dates = { new DateTime(2014, 6, 14, 6, 32, 0),
                   new DateTime(2014, 7, 10, 23, 49, 0),
                   new DateTime(2015, 1, 10, 1, 16, 0),
                   new DateTime(2014, 12, 20, 21, 45, 0),
                   new DateTime(2014, 6, 2, 15, 14, 0) };
    string? output = null;

    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    for (int ctr = 0; ctr < dates.Length; ctr++)
    {
        Console.WriteLine(dates[ctr].ToString("f"));
        output += dates[ctr].ToUniversalTime().ToString("O", CultureInfo.InvariantCulture)
                  + (ctr != dates.Length - 1 ? "|" : "");
    }
    var sw = new StreamWriter(filenameTxt);
    sw.Write(output);
    sw.Close();
    Console.WriteLine("Saved dates...");
}

private static void RestoreDatesAsInvariantStrings()
{
    TimeZoneInfo.ClearCachedData();
    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
    StreamReader sr = new StreamReader(filenameTxt);
    string[] inputValues = sr.ReadToEnd().Split(new char[] { '|' },
                                                StringSplitOptions.RemoveEmptyEntries);
    sr.Close();
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    foreach (var inputValue in inputValues)
    {
        DateTime dateValue;
        if (DateTime.TryParseExact(inputValue, "O", CultureInfo.InvariantCulture,
                              DateTimeStyles.RoundtripKind, out dateValue))
        {
            Console.WriteLine($"'{inputValue}' --> {dateValue.ToLocalTime():f}");
        }
        else
        {
            Console.WriteLine($"Cannot parse '{inputValue}'");
        }
    }
    Console.WriteLine("Restored dates...");
}
// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       '2014-06-14T13:32:00.0000000Z' --> 14 June 2014 14:32
//       '2014-07-11T06:49:00.0000000Z' --> 11 July 2014 07:49
//       '2015-01-10T09:16:00.0000000Z' --> 10 January 2015 09:16
//       '2014-12-21T05:45:00.0000000Z' --> 21 December 2014 05:45
//       '2014-06-02T22:14:00.0000000Z' --> 02 June 2014 23:14
//       Restored dates...

値を整数として保持する

日付と時刻は、ティック数を表す Int64 値として保持できます。 この場合、 DateTime 値が永続化および復元されるシステムのカルチャを考慮する必要はありません。

DateTime値を整数として保持するには:

  1. DateTime値が 1 つの時点を表す場合は、ToUniversalTime メソッドを呼び出して UTC に変換します。
  2. Ticks プロパティから、DateTime 値によって表されるティック数を取得します。

整数として永続化されている DateTime 値を復元するには:

  1. DateTime(Int64) コンストラクターにInt64値を渡して、新しいDateTime オブジェクトをインスタンス化します。
  2. DateTime値が 1 つの時点を表す場合は、ToLocalTime メソッドを呼び出して UTC から現地時刻に変換します。

次の例では、 DateTime 値の配列を整数として、米国太平洋タイム ゾーンのシステムに保持します。 UTC ゾーン内のシステムで復元します。 整数を含むファイルには、その直後のInt64値の合計数を示すInt32値が含まれています。

public static void PersistAsIntegers()
{
    SaveDatesAsInts();
    RestoreDatesAsInts();
}

private static void SaveDatesAsInts()
{
    DateTime[] dates = { new DateTime(2014, 6, 14, 6, 32, 0),
                   new DateTime(2014, 7, 10, 23, 49, 0),
                   new DateTime(2015, 1, 10, 1, 16, 0),
                   new DateTime(2014, 12, 20, 21, 45, 0),
                   new DateTime(2014, 6, 2, 15, 14, 0) };

    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    var ticks = new long[dates.Length];
    for (int ctr = 0; ctr < dates.Length; ctr++)
    {
        Console.WriteLine(dates[ctr].ToString("f"));
        ticks[ctr] = dates[ctr].ToUniversalTime().Ticks;
    }
    var fs = new FileStream(filenameInts, FileMode.Create);
    var bw = new BinaryWriter(fs);
    bw.Write(ticks.Length);
    foreach (var tick in ticks)
        bw.Write(tick);

    bw.Close();
    Console.WriteLine("Saved dates...");
}

private static void RestoreDatesAsInts()
{
    TimeZoneInfo.ClearCachedData();
    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
    FileStream fs = new FileStream(filenameInts, FileMode.Open);
    BinaryReader br = new BinaryReader(fs);
    int items;
    DateTime[] dates;

    try
    {
        items = br.ReadInt32();
        dates = new DateTime[items];

        for (int ctr = 0; ctr < items; ctr++)
        {
            long ticks = br.ReadInt64();
            dates[ctr] = new DateTime(ticks).ToLocalTime();
        }
    }
    catch (EndOfStreamException)
    {
        Console.WriteLine("File corruption detected. Unable to restore data...");
        return;
    }
    catch (IOException)
    {
        Console.WriteLine("Unspecified I/O error. Unable to restore data...");
        return;
    }
    // Thrown during array initialization.
    catch (OutOfMemoryException)
    {
        Console.WriteLine("File corruption detected. Unable to restore data...");
        return;
    }
    finally
    {
        br.Close();
    }

    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    foreach (var value in dates)
        Console.WriteLine(value.ToString("f"));

    Console.WriteLine("Restored dates...");
}
// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       14 June 2014 14:32
//       11 July 2014 07:49
//       10 January 2015 09:16
//       21 December 2014 05:45
//       02 June 2014 23:14
//       Restored dates...

DateTime 値をシリアル化する

ストリームまたはファイルへのシリアル化を通じて DateTime 値を保持し、逆シリアル化を使用して値を復元できます。 DateTime データは、指定されたオブジェクト形式でシリアル化されます。 オブジェクトは逆シリアル化されるときに復元されます。 JsonSerializerXmlSerializerなどのフォーマッタまたはシリアライザーは、シリアル化と逆シリアル化のプロセスを処理します。 シリアル化の詳細と、.NET でサポートされるシリアル化の種類については、「 シリアル化」を参照してください。

次の例では、 XmlSerializer クラスを使用して、 DateTime 値をシリアル化および逆シリアル化します。 この値は、21 世紀のすべての閏年の日を表します。 現在のカルチャが英語 (英国) のシステムで例が実行されている場合、出力は結果を表します。 DateTime オブジェクト自体を逆シリアル化したため、コードは日付と時刻の形式のカルチャの違いを処理する必要はありません。

public static void PersistAsXML()
{
    // Serialize the data.
    var leapYears = new List<DateTime>();
    for (int year = 2000; year <= 2100; year += 4)
    {
        if (DateTime.IsLeapYear(year))
            leapYears.Add(new DateTime(year, 2, 29));
    }
    DateTime[] dateArray = leapYears.ToArray();

    var serializer = new XmlSerializer(dateArray.GetType());
    TextWriter sw = new StreamWriter(filenameXml);

    try
    {
        serializer.Serialize(sw, dateArray);
    }
    catch (InvalidOperationException e)
    {
        Console.WriteLine(e.InnerException?.Message);
    }
    finally
    {
        if (sw != null) sw.Close();
    }

    // Deserialize the data.
    DateTime[]? deserializedDates;
    using (var fs = new FileStream(filenameXml, FileMode.Open))
    {
        deserializedDates = (DateTime[]?)serializer.Deserialize(fs);
    }

    // Display the dates.
    Console.WriteLine($"Leap year days from 2000-2100 on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    int nItems = 0;
    if (deserializedDates is not null)
    {
        foreach (var dat in deserializedDates)
        {
            Console.Write($"   {dat:d}     ");
            nItems++;
            if (nItems % 5 == 0)
                Console.WriteLine();
        }
    }
}
// The example displays the following output:
//    Leap year days from 2000-2100 on an en-GB system:
//       29/02/2000       29/02/2004       29/02/2008       29/02/2012       29/02/2016
//       29/02/2020       29/02/2024       29/02/2028       29/02/2032       29/02/2036
//       29/02/2040       29/02/2044       29/02/2048       29/02/2052       29/02/2056
//       29/02/2060       29/02/2064       29/02/2068       29/02/2072       29/02/2076
//       29/02/2080       29/02/2084       29/02/2088       29/02/2092       29/02/2096

前の例には時間情報は含まれていません。 DateTime値が一瞬の時間を表し、現地時刻として表される場合は、ToUniversalTime メソッドを呼び出してシリアル化する前に、ローカル時刻から UTC に変換します。 逆シリアル化した後、 ToLocalTime メソッドを呼び出して UTC から現地時刻に変換します。

DateTime と TimeSpan

DateTimeTimeSpanの値の型は、DateTimeが一瞬の時間を表すのに対し、TimeSpanは時間間隔を表す点が異なります。 DateTimeのインスタンスを別のインスタンスから減算して、それらの間の時間間隔を表すTimeSpan オブジェクトを取得できます。 または、現在のDateTimeに正のTimeSpanを追加して、将来の日付を表すDateTime値を取得することもできます。

DateTime オブジェクトから時間間隔を加算または減算できます。 時間間隔は負または正の値にすることができ、ティック、秒、 TimeSpan オブジェクトなどの単位で表すことができます。

許容誤差の範囲内で等しいかどうかを比較する

DateTime値の等値比較は正確です。 等しいとみなされるためには、2つの値が同じ刻み数として表されている必要があります。 多くのアプリケーションでは、多くの場合、その精度は不要であるか、間違っています。 多くの場合、 DateTime オブジェクト がほぼ等しいかどうかをテストする必要があります。

次の例では、ほぼ同等の DateTime 値を比較する方法を示します。 等しいと宣言するときに、差の小さな余白を受け入れます。

public static bool RoughlyEquals(DateTime time, DateTime timeWithWindow, int windowInSeconds, int frequencyInSeconds)
{
    long delta = (long)((TimeSpan)(timeWithWindow - time)).TotalSeconds % frequencyInSeconds;
    delta = delta > windowInSeconds ? frequencyInSeconds - delta : delta;
    return Math.Abs(delta) < windowInSeconds;
}

public static void TestRoughlyEquals()
{
    int window = 10;
    int freq = 60 * 60 * 2; // 2 hours;

    DateTime d1 = DateTime.Now;

    DateTime d2 = d1.AddSeconds(2 * window);
    DateTime d3 = d1.AddSeconds(-2 * window);
    DateTime d4 = d1.AddSeconds(window / 2);
    DateTime d5 = d1.AddSeconds(-window / 2);

    DateTime d6 = (d1.AddHours(2)).AddSeconds(2 * window);
    DateTime d7 = (d1.AddHours(2)).AddSeconds(-2 * window);
    DateTime d8 = (d1.AddHours(2)).AddSeconds(window / 2);
    DateTime d9 = (d1.AddHours(2)).AddSeconds(-window / 2);

    Console.WriteLine($"d1 ({d1}) ~= d1 ({d1}): {RoughlyEquals(d1, d1, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d2 ({d2}): {RoughlyEquals(d1, d2, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d3 ({d3}): {RoughlyEquals(d1, d3, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d4 ({d4}): {RoughlyEquals(d1, d4, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d5 ({d5}): {RoughlyEquals(d1, d5, window, freq)}");

    Console.WriteLine($"d1 ({d1}) ~= d6 ({d6}): {RoughlyEquals(d1, d6, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d7 ({d7}): {RoughlyEquals(d1, d7, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d8 ({d8}): {RoughlyEquals(d1, d8, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d9 ({d9}): {RoughlyEquals(d1, d9, window, freq)}");
}
// The example displays output similar to the following:
//    d1 (1/28/2010 9:01:26 PM) ~= d1 (1/28/2010 9:01:26 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d2 (1/28/2010 9:01:46 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d3 (1/28/2010 9:01:06 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d4 (1/28/2010 9:01:31 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d5 (1/28/2010 9:01:21 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d6 (1/28/2010 11:01:46 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d7 (1/28/2010 11:01:06 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d8 (1/28/2010 11:01:31 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d9 (1/28/2010 11:01:21 PM): True

COM インターロップに関する考慮事項

COM アプリケーションに転送された後、マネージド アプリケーションに転送される DateTime 値は、ラウンド トリップと言われます。 ただし、時刻のみを指定する DateTime 値は、想定どおりにラウンドトリップしません。

時刻のみ(例: 午後3時)を往復する場合、最終的な日時は、1 C.E. 年1月1日午後3時ではなく、1899年12月30日午後3時になります。.NETとCOMは、時刻だけが指定された場合、既定の日付を設定します。 ただし、COM システムは 1899 年 12 月 30 日の基準日を想定し、.NET では 0001 年 1 月 1 日の基準日を想定しています。

.NET から COM に時刻のみが渡されると、時刻を COM で使用される形式に変換する特別な処理が実行されます。 COM から .NET に時刻のみが渡された場合、1899 年 12 月 30 日以前に正当な日付と時刻が破損するため、特別な処理は実行されません。 日付が COM からのラウンド トリップを開始した場合、.NET と COM は日付を保持します。

.NET と COM の動作は、アプリケーションが時刻のみを指定する DateTime をラウンドトリップする場合、アプリケーションは、最終的な DateTime オブジェクトの誤った日付を変更または無視することを忘れてはならないことを意味します。


その他のリソース