Практическое руководство. Значения даты и времени круговой поездки

Во многих приложениях значение даты и времени предназначено для однозначного определения одного момента времени. В этой статье показано, как правильно сохранять и восстанавливать значения DateTime и DateTimeOffset, а также значения времени с информацией о часовом поясе, чтобы восстановленное значение определяло то же время, что и сохраненное значение.

Выполнение цикла обработки значения DateTime

  1. Преобразуйте значение DateTime в строковое представление с помощью метода DateTime.ToString(String) с описателем формата "o".

  2. Сохраните строковое представление значения DateTime в файл или передайте его между процессами, доменами приложений или компьютерами.

  3. Получите строку, представляющую значение DateTime.

  4. Вызовите метод DateTime.Parse(String, IFormatProvider, DateTimeStyles) и передайте ему значение DateTimeStyles.RoundtripKind в параметре styles.

В следующем примере показано, как выполнить цикл обработки значения 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 сохранено в системе с тихоокеанским стандартным часовом поясом США, а затем восстановлено в системе с центральным стандартным часовым поясом США, извлеченные дата и время будут на два часа позже исходного времени, что соответствует разнице во времени между часовыми поясами. Однако этот способ не всегда точен для неуказанного времени. Все значения DateTime, для которых свойство Kind имеет значение Unspecified, обрабатываются как значения местного времени. Если это не значение местного времени, DateTime не сможет правильно установить нужный момент времени. Чтобы устранить это ограничение, нужно тесно связать значение даты и времени с его часовым поясом для операций сохранения и восстановления.

Выполнение цикла обработки значения DateTimeOffset

  1. Преобразуйте значение DateTimeOffset в строковое представление с помощью метода DateTimeOffset.ToString(String) с описателем формата "o".

  2. Сохраните строковое представление значения DateTimeOffset в файл или передайте его между процессами, доменами приложений или компьютерами.

  3. Получите строку, представляющую значение DateTimeOffset.

  4. Вызовите метод DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) и передайте ему значение DateTimeStyles.RoundtripKind в параметре styles.

В следующем примере показано, как выполнить цикл обработки значения 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. Полученное значение можно преобразовать в формат UTC с помощью метода DateTimeOffset.ToUniversalTime или в значение времени в определенным часовом поясе с помощью метода DateTimeOffset.ToOffset или TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo). Основное ограничение этого способа — арифметические действия с датами и временем, которые могут дать неточные результаты для значения DateTimeOffset, представляющего время в определенном часовом поясе. Это происходит потому, что значение DateTimeOffset при создании "открепляется" от сведений о часовом поясе. Таким образом, правила коррекции часового пояса не могут быть больше применены при выполнении вычислений с датами и временем. Можно обойти эту проблему, определив пользовательский тип, который содержит значение даты и времени с его соответствующим часовым поясом.

Компиляция кода

В этих примерах требуется импортировать следующие пространства имен с директивами C# using или операторами Visual Basic Imports :

См. также