方法 : 日付と時刻の値をラウンドトリップさせる
更新 : 2007 年 11 月
ある特定の時点を明確に表すように日付と時刻の値を保つことは、多くのアプリケーションに共通する要件です。このトピックでは、DateTime 値、DateTimeOffset 値、およびタイム ゾーン情報を持った日時値を保存する方法、および、保存した日時とまったく同じ時点を表すように復元する方法について説明します。
DateTime 値をラウンドトリップさせるには
DateTime.ToString(String) メソッドと "o" 書式指定子を使用して、DateTime 値を対応する文字列形式に変換します。
DateTime 値の文字列形式をファイルに保存するか、プロセス、アプリケーション ドメイン、またはマシン境界に渡します。
DateTime 値を表す文字列を取得します。
DateTime.Parse(String, IFormatProvider, DateTimeStyles) メソッドを呼び出し、styles パラメータの値として DateTimeStyles.RoundtripKind を渡します。
DateTime の値をラウンドトリップさせる方法を次の例に示します。
Const fileName As String = ".\DateFile.txt"
Dim outFile As New StreamWriter(fileName)
' Save DateTime value.
Dim dateToSave As Date = DateTime.SpecifyKind(#06/12/2008 6:45:15 PM#, _
DateTimeKind.Local)
Dim dateString As String = dateToSave.ToString("o")
Console.WriteLine("Converted {0} ({1}) to {2}.", dateToSave.ToString(), _
dateToSave.Kind.ToString(), dateString)
outFile.WriteLine(dateString)
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName)
outFile.Close()
' Restore DateTime value.
Dim restoredDate As Date
Dim inFile As New StreamReader(fileName)
dateString = inFile.ReadLine()
inFile.Close()
restoredDate = DateTime.Parse(dateString, Nothing, DateTimeStyles.RoundTripKind)
Console.WriteLine("Read {0} ({2}) from {1}.", restoredDate.ToString(), _
fileName, restoredDAte.Kind.ToString())
' The example displays the following output:
' Converted 6/12/2008 6:45:15 PM (Local) to 2008-06-12T18:45:15.0000000-05:00.
' Wrote 2008-06-12T18:45:15.0000000-05:00 to .\DateFile.txt.
' Read 6/12/2008 6:45:15 PM (Local) from .\DateFile.txt.
const string fileName = @".\DateFile.txt";
StreamWriter outFile = new StreamWriter(fileName);
// Save DateTime value.
DateTime dateToSave = DateTime.SpecifyKind(new DateTime(2008, 6, 12, 18, 45, 15),
DateTimeKind.Local);
string dateString = dateToSave.ToString("o");
Console.WriteLine("Converted {0} ({1}) to {2}.",
dateToSave.ToString(),
dateToSave.Kind.ToString(),
dateString);
outFile.WriteLine(dateString);
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName);
outFile.Close();
// Restore DateTime value.
DateTime restoredDate;
StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();
inFile.Close();
restoredDate = DateTime.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Read {0} ({2}) from {1}.", restoredDate.ToString(),
fileName,
restoredDate.Kind.ToString());
// The example displays the following output:
// Converted 6/12/2008 6:45:15 PM (Local) to 2008-06-12T18:45:15.0000000-05:00.
// Wrote 2008-06-12T18:45:15.0000000-05:00 to .\DateFile.txt.
// Read 6/12/2008 6:45:15 PM (Local) from .\DateFile.txt.
DateTime の値をラウンドトリップさせる場合、この方法により、あらゆる現地時刻と協定世界時刻を適切に保存できます。たとえば、現地時間の DateTime 値を米国太平洋標準時ゾーンのシステムで保存し、米国中部標準時ゾーンのシステムで復元できます。復元された日時は、2 つのタイム ゾーン間の時差を反映し、元の時刻の 2 時間遅れの時刻となります。ただし、タイム ゾーンが指定されていない時刻の場合、この方法では必ずしも正確な結果を得ることができません。Kind プロパティが Unspecified である DateTime 値はすべて現地時刻として扱われます。現地時刻以外では、DateTime が間違った時点を示すことになります。この制限は、日付と時刻の値に、該当するタイム ゾーンを確実に関連付けた上で、保存操作と復元操作を行うことによって回避できます。
DateTimeOffset 値をラウンドトリップさせるには
DateTimeOffset.ToString(String) メソッドと "o" 書式指定子を使用して、DateTimeOffset 値を対応する文字列形式に変換します。
DateTimeOffset 値の文字列形式をファイルに保存するか、プロセス、アプリケーション ドメイン、またはマシン境界に渡します。
DateTimeOffset 値を表す文字列を取得します。
DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) メソッドを呼び出し、styles パラメータの値として DateTimeStyles.RoundtripKind を渡します。
DateTimeOffset の値をラウンドトリップさせる方法を次の例に示します。
Const fileName As String = ".\DateOff.txt"
Dim outFile As New StreamWriter(fileName)
' Save DateTime value.
Dim dateToSave As New DateTimeOffset(2008, 6, 12, 18, 45, 15, _
New TimeSpan(7, 0, 0))
Dim dateString As String = dateToSave.ToString("o")
Console.WriteLine("Converted {0} to {1}.", dateToSave.ToString(), dateString)
outFile.WriteLine(dateString)
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName)
outFile.Close()
' Restore DateTime value.
Dim restoredDateOff As DateTimeOffset
Dim inFile As New StreamReader(fileName)
dateString = inFile.ReadLine()
inFile.Close()
restoredDateOff = DateTimeOffset.Parse(dateString, Nothing, DateTimeStyles.RoundTripKind)
Console.WriteLine("Read {0} from {1}.", restoredDateOff.ToString(), fileName)
' The example displays the following output:
' Converted 6/12/2008 6:45:15 PM +07:00 to 2008-06-12T18:45:15.0000000+07:00.
' Wrote 2008-06-12T18:45:15.0000000+07:00 to .\DateOff.txt.
' Read 6/12/2008 6:45:15 PM +07:00 from .\DateOff.txt.
const string fileName = @".\DateOff.txt";
StreamWriter outFile = new StreamWriter(fileName);
// Save DateTime value.
DateTimeOffset dateToSave = new DateTimeOffset(2008, 6, 12, 18, 45, 15,
new TimeSpan(7, 0, 0));
string dateString = dateToSave.ToString("o");
Console.WriteLine("Converted {0} to {1}.", dateToSave.ToString(),
dateString);
outFile.WriteLine(dateString);
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName);
outFile.Close();
// Restore DateTime value.
DateTimeOffset restoredDateOff;
StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();
inFile.Close();
restoredDateOff = DateTimeOffset.Parse(dateString, null,
DateTimeStyles.RoundtripKind);
Console.WriteLine("Read {0} from {1}.", restoredDateOff.ToString(),
fileName);
// The example displays the following output:
// Converted 6/12/2008 6:45:15 PM +07:00 to 2008-06-12T18:45:15.0000000+07:00.
// Wrote 2008-06-12T18:45:15.0000000+07:00 to .\DateOff.txt.
// Read 6/12/2008 6:45:15 PM +07:00 from .\DateOff.txt.
この方法により、DateTimeOffset の値が、常にある特定の時点として明確に識別されます。その後、DateTimeOffset.ToUniversalTime メソッドを呼び出すことによって、この値を世界協定時刻 (UTC) に変換できます。また、DateTimeOffset.ToOffset メソッドまたは TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) メソッドを呼び出すことによって、特定のタイム ゾーンの時刻に変換することもできます。この方法には、特定のタイム ゾーンの時刻を表す DateTimeOffset の値に対して日付と時刻の演算を行った場合、そのタイム ゾーンにおける正確な結果を得ることができないという重要な制限があります。これは、DateTimeOffset の値をインスタンス化すると、対応するタイム ゾーンとの関連付けが解除されるためです。したがって、日付と時刻の計算を実行した場合、タイム ゾーンの調整規則は適用されません。この問題は、日付値と時刻値、および付随するタイム ゾーンを保持するカスタム型を定義することによって回避できます。
対応するタイム ゾーンと共に日付と時刻の値をラウンドトリップさせるには
2 つのフィールドを持ったクラスまたは構造体を定義します。1 つ目のフィールドは DateTime オブジェクトまたは DateTimeOffset オブジェクトに、2 つ目のフィールドは TimeZoneInfo オブジェクトにします。これを踏まえた単純な型の例を次に示します。
<Serializable> Public Class DateInTimeZone Private tz As TimeZoneInfo Private thisDate As DateTimeOffset Public Sub New() End Sub Public Sub New(date1 As DateTimeOffset, timeZone As TimeZoneInfo) If timeZone Is Nothing Then Throw New ArgumentNullException("The time zone cannot be null.") End If Me.thisDate = date1 Me.tz = timeZone End Sub Public Property DateAndTime As DateTimeOffset Get Return Me.thisDate End Get Set If Value.Offset <> Me.tz.GetUtcOffset(Value) Then Me.thisDate = TimeZoneInfo.ConvertTime(Value, tz) Else Me.thisDate = Value End If End Set End Property Public ReadOnly Property TimeZone As TimeZoneInfo Get Return tz End Get End Property End Class
[Serializable] public class DateInTimeZone { private TimeZoneInfo tz; private DateTimeOffset thisDate; public DateInTimeZone() {} public DateInTimeZone(DateTimeOffset date, TimeZoneInfo timeZone) { if (timeZone == null) throw new ArgumentNullException("The time zone cannot be null."); this.thisDate = date; this.tz = timeZone; } public DateTimeOffset DateAndTime { get { return this.thisDate; } set { if (value.Offset != this.tz.GetUtcOffset(value)) this.thisDate = TimeZoneInfo.ConvertTime(value, tz); else this.thisDate = value; } } public TimeZoneInfo TimeZone { get { return this.tz; } } }
このクラスに SerializableAttribute 属性を適用します。
BinaryFormatter.Serialize メソッドを使用してオブジェクトをシリアル化します。
Deserialize メソッドを使用してオブジェクトを復元します。
逆シリアル化したオブジェクトを適切な型のオブジェクトにキャスト (C# の場合) または変換 (Visual Basic の場合) します。
日付値と時刻値およびタイム ゾーン情報が格納されたオブジェクトをラウンドトリップさせる方法を次の例に示します。
Const fileName As String = ".\DateWithTz.dat"
Dim tempDate As Date = #9/3/2008 7:00:00 PM#
Dim tempTz As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
Dim dateWithTz As New DateInTimeZone(New DateTimeOffset(tempDate, _
tempTz.GetUtcOffset(tempDate)), _
tempTz)
' Store DateInTimeZone value to a file
Dim outFile As New FileStream(fileName, FileMode.Create)
Try
Dim formatter As New BinaryFormatter()
formatter.Serialize(outFile, dateWithTz)
Console.WriteLine("Saving {0} {1} to {2}", dateWithTz.DateAndTime, _
IIf(dateWithTz.TimeZone.IsDaylightSavingTime(dateWithTz.DateAndTime), _
dateWithTz.TimeZone.DaylightName, dateWithTz.TimeZone.DaylightName), _
fileName)
Catch e As SerializationException
Console.WriteLine("Unable to serialize time data to {0}.", fileName)
Finally
outFile.Close()
End Try
' Retrieve DateInTimeZone value
If File.Exists(fileName) Then
Dim inFile As New FileStream(fileName, FileMode.Open)
Dim dateWithTz2 As New DateInTimeZone()
Try
Dim formatter As New BinaryFormatter()
dateWithTz2 = DirectCast(formatter.Deserialize(inFile), DateInTimeZone)
Console.WriteLine("Restored {0} {1} from {2}", dateWithTz2.DateAndTime, _
IIf(dateWithTz2.TimeZone.IsDaylightSavingTime(dateWithTz2.DateAndTime), _
dateWithTz2.TimeZone.DaylightName, dateWithTz2.TimeZone.DaylightName), _
fileName)
Catch e As SerializationException
Console.WriteLine("Unable to retrieve date and time information from {0}", _
fileName)
Finally
inFile.Close
End Try
End If
' This example displays the following output to the console:
' Saving 9/3/2008 7:00:00 PM -05:00 Central Daylight Time to .\DateWithTz.dat
' Restored 9/3/2008 7:00:00 PM -05:00 Central Daylight Time from .\DateWithTz.dat
const string fileName = @".\DateWithTz.dat";
DateTime tempDate = new DateTime(2008, 9, 3, 19, 0, 0);
TimeZoneInfo tempTz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateInTimeZone dateWithTz = new DateInTimeZone(new DateTimeOffset(tempDate,
tempTz.GetUtcOffset(tempDate)),
tempTz);
// Store DateInTimeZone value to a file
FileStream outFile = new FileStream(fileName, FileMode.Create);
try
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(outFile, dateWithTz);
Console.WriteLine("Saving {0} {1} to {2}", dateWithTz.DateAndTime,
dateWithTz.TimeZone.IsDaylightSavingTime(dateWithTz.DateAndTime) ?
dateWithTz.TimeZone.DaylightName : dateWithTz.TimeZone.DaylightName,
fileName);
}
catch (SerializationException)
{
Console.WriteLine("Unable to serialize time data to {0}.", fileName);
}
finally
{
outFile.Close();
}
// Retrieve DateInTimeZone value
if (File.Exists(fileName))
{
FileStream inFile = new FileStream(fileName, FileMode.Open);
DateInTimeZone dateWithTz2 = new DateInTimeZone();
try
{
BinaryFormatter formatter = new BinaryFormatter();
dateWithTz2 = formatter.Deserialize(inFile) as DateInTimeZone;
Console.WriteLine("Restored {0} {1} from {2}", dateWithTz2.DateAndTime,
dateWithTz2.TimeZone.IsDaylightSavingTime(dateWithTz2.DateAndTime) ?
dateWithTz2.TimeZone.DaylightName : dateWithTz2.TimeZone.DaylightName,
fileName);
}
catch (SerializationException)
{
Console.WriteLine("Unable to retrieve date and time information from {0}",
fileName);
}
finally
{
inFile.Close();
}
}
// This example displays the following output to the console:
// Saving 9/3/2008 7:00:00 PM -05:00 Central Daylight Time to .\DateWithTz.dat
// Restored 9/3/2008 7:00:00 PM -05:00 Central Daylight Time from .\DateWithTz.dat
この方法では、日付、時刻、およびタイム ゾーンの組み合わせを保持するオブジェクトが、日付値とタイム ゾーン値を確実に同期するように実装されている場合、保存と復元の前後で正確な時点が常に明確に反映されます。
コードのコンパイル方法
これらの例では、次の項目が必要です。
C# の using ステートメントまたは Visual Basic の Imports ステートメントで次の名前空間がインポートされていること。
System.Core.dll が参照設定されていること。
DateInTimeZone クラス以外のすべてのコード例は、クラスまたは Visual Basic のモジュールのメソッドとして記述し、Main メソッドから呼び出すこと。