如何:往返日期和时间值

在许多应用程序中,日期和时间值旨在明确标识单个时间点。 本文演示了如何保存和还原 DateTime 值、DateTimeOffset 值以及包含时区信息的日期和时间值,以便还原后的值与保存的值标识的时间相同。

往返 DateTime 值

  1. 通过调用包含 "o" 格式说明符的 DateTime.ToString(String) 方法,将 DateTime 值转换为字符串表示形式。

  2. DateTime 值的字符串表示形式保存到文件中,或跨进程、应用域或计算机边界传递它。

  3. 检索表示 DateTime 值的字符串。

  4. 调用 DateTime.Parse(String, IFormatProvider, DateTimeStyles) 方法,并以 styles 参数值的形式传递 DateTimeStyles.RoundtripKind

下面的示例展示了如何往返 DateTime 值。

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;

using StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();

if (dateString is not null)
{
    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.
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.

往返 DateTime 值时,此方法成功暂留所有本地时间和世界时间。 例如,如果本地 DateTime 值保存在采用美国太平洋标准时区的系统会,并在位于美国中部标准时区的系统上还原,则还原的日期和时间会比原始时间晚两个小时,这反映了两个时区之间的时差。 但是,此方法对于未指定时间不一定准确。 所有 Kind 属性为 UnspecifiedDateTime 值都会被视为本地时间。 如果不是本地时间,则 DateTime 不会成功标识正确的时间点。 针对此限制的解决方法是将日期和时间值与其时区紧密耦合,以便进行保存和还原操作。

往返 DateTimeOffset 值

  1. 通过调用包含 "o" 格式说明符的 DateTimeOffset.ToString(String) 方法,将 DateTimeOffset 值转换为字符串表示形式。

  2. DateTimeOffset 值的字符串表示形式保存到文件中,或跨进程、应用域或计算机边界传递它。

  3. 检索表示 DateTimeOffset 值的字符串。

  4. 调用 DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) 方法,并以 styles 参数值的形式传递 DateTimeStyles.RoundtripKind

下面的示例展示了如何往返 DateTimeOffset 值。

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;

using StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();

if (dateString is not null)
{
    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.
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.

此方法始终将 DateTimeOffset 值明确标识为单个时间点。 然后,可以调用 DateTimeOffset.ToUniversalTime 方法,将此值转换为协调世界时 (UTC);也可以调用 DateTimeOffset.ToOffsetTimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) 方法,将此值转换为特定时区时间。 此方法的主要限制在于,如果对表示特定时区时间的 DateTimeOffset 值执行日期和时间算术,生成的结果对于相应时区来说可能并不准确。 这是因为 DateTimeOffset 值在实例化时就与时区解除关联。 因此,执行日期和时间计算时,无法再应用该时区的调整规则。 可以通过定义包含日期和时间值以及其随附时区的自定义类型,来解决此问题。

编译代码

这些示例要求使用 C# using 指令或 Visual Basic Imports 语句导入下列命名空间:

请参阅