Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье приводятся дополнительные замечания к справочной документации по этому API.
Это важно
Эры в японских календарях основаны на царствии императора и поэтому, как ожидается, изменятся. Например, 1 мая 2019 г. отмечено начало эпохи Reiwa в JapaneseCalendar и JapaneseLunisolarCalendar. Такое изменение эпохи влияет на все приложения, использующие эти календари. Для получения дополнительной информации и определения влияния на ваши приложения см. статью Обработка новой эпохи в японском календаре в .NET. Сведения о тестировании ваших приложений на системах Windows для обеспечения их готовности к изменению эпохи см. в разделе Подготовка приложения к изменению японской эпохи. Функции в .NET, поддерживающие календари с несколькими эрами, и рекомендации по работе с календарями, поддерживающими несколько эпох, см. в разделе Работа с эрами.
Обзор
Тип значения DateTime представляет даты и время со значениями в диапазоне от 00:00:00 (полуночи), 1 января 0001 г. нашей эры (н. э.) до 11:59:59, 31 декабря 9999 г. в григорианском календаре.
Значения времени измеряются в 100-наносекундных единицах, называемых галками. Конкретная дата — это количество галок с 12:00 полуночи, 1 января 0001 Г. (C.E.) в календаре GregorianCalendar. Число исключает отсчёты времени, добавляемые високосными секундами. Например, значение галочки 31241376000000000L представляет дату пятницы, 01 января 0100 12:00:00 полуночи. Значение DateTime всегда выражается в контексте явного или стандартного календаря.
Примечание.
Если вы работаете со значением тиков, которое необходимо преобразовать в другой интервал времени, например минуты или секунды, следует использовать константу TimeSpan.TicksPerDay, TimeSpan.TicksPerHour, TimeSpan.TicksPerMinute, TimeSpan.TicksPerSecondили TimeSpan.TicksPerMillisecond для выполнения преобразования. Например, чтобы добавить количество секунд, представленных указанным числом галок, к компоненту Second значения DateTime, можно использовать выражение dateValue.Second + nTicks/Timespan.TicksPerSecond
.
Вы можете просмотреть источник для всего набора примеров из этой статьи в Visual Basic, F#или C#.
Примечание.
Альтернативой структуре DateTime для работы со значениями даты и времени в частности часовых поясов является структура DateTimeOffset. Структура DateTimeOffset хранит сведения о дате и времени в частном поле DateTime и количество минут, по которым эта дата и время отличается от utc в частном поле Int16. Это позволяет DateTimeOffset значению отражать время в определенном часовом поясе, в то время как DateTime значение может однозначно отражать только время в формате UTC и времени местного часового пояса. Обсуждение того, когда следует использовать структуру DateTime или структуру DateTimeOffset при работе со значениями даты и времени, см. в разделе выбор между dateTime, DateTimeOffset, TimeSpan и TimeZoneInfo.
Краткие ссылки на пример кода
Примечание.
Некоторые примеры C# в этой статье выполняются в Try.NET встроенном средстве выполнения кода и интерактивной среде. Нажмите кнопку запуска , чтобы запустить пример в интерактивном окне. После выполнения кода его можно изменить и запустить измененный код, выбрав выполнить еще раз. Измененный код выполняется в интерактивном окне или, если компиляция завершается ошибкой, в интерактивном окне отображаются все сообщения об ошибках компилятора C#.
Местный часовой пояс площадки и средства запуска кода Try.NET — это Всемирное координированное время (UTC). Это может повлиять на работу и выходные данные примеров, иллюстрирующих DateTime, DateTimeOffset, типы TimeZoneInfo и их члены.
В этой статье приведено несколько примеров использования типа DateTime
:
Примеры инициализации
- Вызов конструктора
- Вызов неявного конструктора без параметров
- Присваивание из возвращаемого значения
- Разбор строки, представляющей дату и время
- синтаксис Visual Basic для инициализации даты и времени
Форматирование объектов DateTime
в виде строковых примеров
- Использовать формат даты и времени по умолчанию
- Форматирование даты и времени с помощью определенной культуры
- Форматирование даты и времени с использованием стандартной или пользовательской форматированной строки
- Укажите строку формата и определенную культуру
- Форматирование даты с помощью стандарта ISO 8601 для веб-служб
Анализ строк в виде примеров объектов DateTime
-
использовать
Parse
илиTryParse
, чтобы преобразовать строку в дату и время -
использовать
ParseExact
илиTryParseExact
для преобразования строки в известном формате - Преобразование из строкового представления ISO 8601 в дату и время
Примеры разрешения DateTime
Примеры культуры и календарей
- Отображение значений даты и времени с использованием культуроспецифических календарей
- Выполнять разбор строк в соответствии с календарем, зависящим от культуры
- Инициализация даты и времени из календаря конкретной культуры
- доступ к свойствам даты и времени с помощью календаря конкретной культуры
- Определение недели в году с использованием культурно-специфических календарей
Примеры сохраняемости
- Сохранение значений даты и времени в виде строк в локальном часовом поясе
- Сохранение значений даты и времени в виде строк в инвариантном формате, независимом от культуры и времени
- Сохранение значений даты и времени в виде целых чисел
-
Сохранение значений даты и времени с помощью
XmlSerializer
Инициализация объекта DateTime
Начальное значение можно назначить новому значению DateTime
различными способами:
- Вызов конструктора либо в том месте, где указаны аргументы для значений, либо используйте неявный конструктор без параметров.
- Назначение
DateTime
возвращаемого значения свойства или метода. - Анализ значения
DateTime
из строкового представления. - Использование специфичных для Visual Basic функций языка для создания экземпляра
DateTime
.
В следующих фрагментах кода показаны примеры каждого из них.
Вызов конструкторов
Вы вызываете любые перегрузки конструктора DateTime, которые указывают элементы значения даты и времени (например, год, месяц и день или число галок). Следующий код создает определенную дату с помощью конструктора DateTime, указывающего год, месяц, день, час, минуту и секунду.
Dim date1 As New Date(2008, 5, 1, 8, 30, 52)
var date1 = new DateTime(2008, 5, 1, 8, 30, 52);
Console.WriteLine(date1);
let date1 = DateTime(2008, 5, 1, 8, 30, 52)
printfn $"{date1}"
Вы вызываете неявный конструктор структуры DateTime
без параметров, когда нужно, чтобы DateTime
было инициализировано до его значения по умолчанию. (Дополнительные сведения о неявном конструкторе типа значения без параметров см. в разделе "Типы значений".) Некоторые компиляторы также поддерживают объявление значения DateTime без явного назначения значения. Создание значения без явной инициализации также приводит к значению по умолчанию. В следующем примере показан неявный конструктор без параметров DateTime в C# и Visual Basic, а также объявление DateTime без назначения в Visual Basic.
Dim dat1 As 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(Date.MinValue))
Dim dat2 As New DateTime()
' The following method call displays 1/1/0001 12:00:00 AM.
Console.WriteLine(dat2.ToString(System.Globalization.CultureInfo.InvariantCulture))
' The following method call displays True.
Console.WriteLine(dat2.Equals(Date.MinValue))
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));
let dat1 = DateTime()
// The following method call displays 1/1/0001 12:00:00 AM.
printfn $"{dat1.ToString System.Globalization.CultureInfo.InvariantCulture}"
// The following method call displays True.
printfn $"{dat1.Equals DateTime.MinValue}"
Назначьте вычисляемое значение
Объекту DateTime можно присвоить значение даты и времени, которое возвращается свойством или методом. В следующем примере назначается текущая дата и время, текущая дата и время в формате UTC, а также текущая дата для трех новых переменных DateTime.
Dim date1 As Date = Date.Now
Dim date2 As Date = Date.UtcNow
Dim date3 As Date = Date.Today
DateTime date1 = DateTime.Now;
DateTime date2 = DateTime.UtcNow;
DateTime date3 = DateTime.Today;
let date1 = DateTime.Now
let date2 = DateTime.UtcNow
let date3 = DateTime.Today
Разбор строки, содержащей сведения о дате и времени.
Методы Parse, ParseExact, TryParseи TryParseExact преобразуют строку в эквивалентное значение даты и времени. В следующих примерах используются методы Parse и ParseExact для анализа строки и преобразования его в значение DateTime. Второй формат использует форму , поддерживаемую стандартом ISO 8601, для представления даты и времени в строковом формате. Это стандартное представление часто используется для передачи сведений о дате в веб-службах.
Dim dateString As String = "5/1/2008 8:30:52 AM"
Dim date1 As Date = Date.Parse(dateString,
System.Globalization.CultureInfo.InvariantCulture)
Dim iso8601String As String = "20080501T08:30:52Z"
Dim dateISO8602 As Date = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
System.Globalization.CultureInfo.InvariantCulture)
Console.WriteLine(dateISO8602)
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);
let dateString = "5/1/2008 8:30:52 AM"
let date1 = DateTime.Parse(dateString, System.Globalization.CultureInfo.InvariantCulture)
let iso8601String = "20080501T08:30:52Z"
let 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 представлены как количество тиков (число 100-наносекундных интервалов), прошедших с полуночи 1 января 0001 года. Фактическое 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
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"{date1.ToString()}"
// For en-US culture, displays 3/1/2008 7:00:00 AM
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString())
' For en-US culture, displays 3/1/2008 7:00:00 AM
Может потребоваться отформатировать даты в определенной культурной среде для поддержки веб-сценариев, где сервер и клиент могут использовать разные культурные настройки. Вы указываете культуру с помощью метода 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
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"""{date1.ToString(System.Globalization.CultureInfo.CreateSpecificCulture "fr-FR")}"""
// Displays 01/03/2008 07:00:00
Dim date1 As Date = #3/1/2008 7:00AM#
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
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"""{date1.ToString "F"}"""
// Displays Saturday, March 01, 2008 7:00:00 AM
Dim date1 As Date = #3/1/2008 7:00AM#
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
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"""{date1.ToString("F", new System.Globalization.CultureInfo "fr-FR")}"""
// Displays samedi 1 mars 2008 07:00:00
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString("F", New System.Globalization.CultureInfo("fr-FR")))
' Displays samedi 1 mars 2008 07:00:00
Перегрузка DateTime.ToString(String) также может использоваться с настраиваемой строкой форматирования для указания других форматов. В следующем примере показано, как отформатировать строку с помощью стандартного формата ISO 8601 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
let date1 = DateTime(2008, 3, 1, 7, 0, 0, DateTimeKind.Utc)
printfn $"""{date1.ToString("yyyy-MM-ddTHH:mm:sszzz", System.Globalization.CultureInfo.InvariantCulture)}"""
// Displays 2008-03-01T07:00:00+00:00
Dim date1 As DateTime = 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. Как правило, строки даты и времени используют два разных использования в приложениях:
Дата и время может принимать различные формы и отражает традиции либо текущей культуры, либо специфической культуры. Например, приложение позволяет пользователю, текущая культура которого обозначена как en-US, вводить значение даты как "15.12.2013" или "15 декабря 2013 года". Он позволяет пользователю, чья текущая культурная настройка en-gb, вводить значение даты как "15.12.2013" или "15 декабря 2013 года".
Дата и время представлены в предопределенном формате. Например, приложение сериализует дату как "20130103" независимо от культуры, на которой оно работает. Приложению может потребоваться ввод дат в коротком формате текущей культуры.
Метод Parse или TryParse используется для преобразования строки из одного из распространенных форматов даты и времени, используемых в культуре, в формат значения 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.
System.Threading.Thread.CurrentThread.CurrentCulture <-
System.Globalization.CultureInfo.CreateSpecificCulture "en-GB"
let date1 = DateTime(2013, 6, 1, 12, 32, 30)
let badFormats = ResizeArray<String>()
printfn "%-37s %-19s\n" "Date String" "Date"
for dateString in date1.GetDateTimeFormats() do
match DateTime.TryParse dateString with
| true, parsedDate ->
printfn $"%-37s{dateString} %-19O{parsedDate}\n"
| _ ->
badFormats.Add dateString
// Display strings that could not be parsed.
if badFormats.Count > 0 then
printfn "\nStrings that could not be parsed: "
for badFormat in badFormats do
printfn $" {badFormat}"
// Press "Run" to see the output.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
Dim date1 As New DateTime(2013, 6, 1, 12, 32, 30)
Dim badFormats As New List(Of String)
Console.WriteLine($"{"Date String",-37} {"Date",-19}")
Console.WriteLine()
For Each dateString As String In date1.GetDateTimeFormats()
Dim parsedDate As DateTime
If DateTime.TryParse(dateString, parsedDate) Then
Console.WriteLine($"{dateString,-37} {DateTime.Parse(dateString),-19:g}")
Else
badFormats.Add(dateString)
End If
Next
' Display strings that could not be parsed.
If badFormats.Count > 0 Then
Console.WriteLine()
Console.WriteLine("Strings that could not be parsed: ")
For Each badFormat In badFormats
Console.WriteLine($" {badFormat}")
Next
End If
' The example displays the following output:
' Date String Date
'
' 01/06/2013 01/06/2013 00:00:00
' 01/06/13 01/06/2013 00:00:00
' 1/6/13 01/06/2013 00:00:00
' 1.6.13 01/06/2013 00:00:00
' 2013-06-01 01/06/2013 00:00:00
' 01 June 2013 01/06/2013 00:00:00
' 1 June 2013 01/06/2013 00:00:00
' 01 June 2013 12:32 01/06/2013 12:32:00
' 01 June 2013 12:32 01/06/2013 12:32:00
' 01 June 2013 12:32 PM 01/06/2013 12:32:00
' 01 June 2013 12:32 PM 01/06/2013 12:32:00
' 1 June 2013 12:32 01/06/2013 12:32:00
' 1 June 2013 12:32 01/06/2013 12:32:00
' 1 June 2013 12:32 PM 01/06/2013 12:32:00
' 1 June 2013 12:32 PM 01/06/2013 12:32:00
' 01 June 2013 12:32:30 01/06/2013 12:32:30
' 01 June 2013 12:32:30 01/06/2013 12:32:30
' 01 June 2013 12:32:30 PM 01/06/2013 12:32:30
' 01 June 2013 12:32:30 PM 01/06/2013 12:32:30
' 1 June 2013 12:32:30 01/06/2013 12:32:30
' 1 June 2013 12:32:30 01/06/2013 12:32:30
' 1 June 2013 12:32:30 PM 01/06/2013 12:32:30
' 1 June 2013 12:32:30 PM 01/06/2013 12:32:30
' 01/06/2013 12:32 01/06/2013 12:32:00
' 01/06/2013 12:32 01/06/2013 12:32:00
' 01/06/2013 12:32 PM 01/06/2013 12:32:00
' 01/06/2013 12:32 PM 01/06/2013 12:32:00
' 01/06/13 12:32 01/06/2013 12:32:00
' 01/06/13 12:32 01/06/2013 12:32:00
' 01/06/13 12:32 PM 01/06/2013 12:32:00
' 01/06/13 12:32 PM 01/06/2013 12:32:00
' 1/6/13 12:32 01/06/2013 12:32:00
' 1/6/13 12:32 01/06/2013 12:32:00
' 1/6/13 12:32 PM 01/06/2013 12:32:00
' 1/6/13 12:32 PM 01/06/2013 12:32:00
' 1.6.13 12:32 01/06/2013 12:32:00
' 1.6.13 12:32 01/06/2013 12:32:00
' 1.6.13 12:32 PM 01/06/2013 12:32:00
' 1.6.13 12:32 PM 01/06/2013 12:32:00
' 2013-06-01 12:32 01/06/2013 12:32:00
' 2013-06-01 12:32 01/06/2013 12:32:00
' 2013-06-01 12:32 PM 01/06/2013 12:32:00
' 2013-06-01 12:32 PM 01/06/2013 12:32:00
' 01/06/2013 12:32:30 01/06/2013 12:32:30
' 01/06/2013 12:32:30 01/06/2013 12:32:30
' 01/06/2013 12:32:30 PM 01/06/2013 12:32:30
' 01/06/2013 12:32:30 PM 01/06/2013 12:32:30
' 01/06/13 12:32:30 01/06/2013 12:32:30
' 01/06/13 12:32:30 01/06/2013 12:32:30
' 01/06/13 12:32:30 PM 01/06/2013 12:32:30
' 01/06/13 12:32:30 PM 01/06/2013 12:32:30
' 1/6/13 12:32:30 01/06/2013 12:32:30
' 1/6/13 12:32:30 01/06/2013 12:32:30
' 1/6/13 12:32:30 PM 01/06/2013 12:32:30
' 1/6/13 12:32:30 PM 01/06/2013 12:32:30
' 1.6.13 12:32:30 01/06/2013 12:32:30
' 1.6.13 12:32:30 01/06/2013 12:32:30
' 1.6.13 12:32:30 PM 01/06/2013 12:32:30
' 1.6.13 12:32:30 PM 01/06/2013 12:32:30
' 2013-06-01 12:32:30 01/06/2013 12:32:30
' 2013-06-01 12:32:30 01/06/2013 12:32:30
' 2013-06-01 12:32:30 PM 01/06/2013 12:32:30
' 2013-06-01 12:32:30 PM 01/06/2013 12:32:30
' 01 June 01/06/2013 00:00:00
' 01 June 01/06/2013 00:00:00
' 2013-06-01T12:32:30.0000000 01/06/2013 12:32:30
' 2013-06-01T12:32:30.0000000 01/06/2013 12:32:30
' Sat, 01 Jun 2013 12:32:30 GMT 01/06/2013 05:32:30
' Sat, 01 Jun 2013 12:32:30 GMT 01/06/2013 05:32:30
' 2013-06-01T12:32:30 01/06/2013 12:32:30
' 12:32 22/04/2013 12:32:00
' 12:32 22/04/2013 12:32:00
' 12:32 PM 22/04/2013 12:32:00
' 12:32 PM 22/04/2013 12:32:00
' 12:32:30 22/04/2013 12:32:30
' 12:32:30 22/04/2013 12:32:30
' 12:32:30 PM 22/04/2013 12:32:30
' 12:32:30 PM 22/04/2013 12:32:30
' 2013-06-01 12:32:30Z 01/06/2013 05:32:30
' 01 June 2013 19:32:30 01/06/2013 19:32:30
' 01 June 2013 19:32:30 01/06/2013 19:32:30
' 01 June 2013 07:32:30 PM 01/06/2013 19:32:30
' 01 June 2013 7:32:30 PM 01/06/2013 19:32:30
' 1 June 2013 19:32:30 01/06/2013 19:32:30
' 1 June 2013 19:32:30 01/06/2013 19:32:30
' 1 June 2013 07:32:30 PM 01/06/2013 19:32:30
' 1 June 2013 7:32:30 PM 01/06/2013 19:32:30
' June 2013 01/06/2013 00:00:00
' June 2013 01/06/2013 00:00:00
Методы ParseExact и TryParseExact используются для преобразования строки, которую необходимо привести к определенному формату или форматам в значение DateTime. В качестве параметра в методе синтаксического анализа указывается одна или несколько строк формата даты и времени. В следующем примере используется метод 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
let formats = [| "yyyyMMdd"; "HHmmss" |]
let dateStrings =
[ "20130816"; "20131608"; " 20130816 "
"115216"; "521116"; " 115216 " ]
for dateString in dateStrings do
match DateTime.TryParseExact(dateString, formats, null,
System.Globalization.DateTimeStyles.AllowWhiteSpaces |||
System.Globalization.DateTimeStyles.AdjustToUniversal) with
| true, parsedDate ->
printfn $"{dateString} --> {parsedDate:g}"
| _ ->
printfn $"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
Dim formats() As String = {"yyyyMMdd", "HHmmss"}
Dim dateStrings() As String = {"20130816", "20131608",
" 20130816 ", "115216",
"521116", " 115216 "}
Dim parsedDate As DateTime
For Each dateString As String In dateStrings
If DateTime.TryParseExact(dateString, formats, Nothing,
DateTimeStyles.AllowWhiteSpaces Or
DateTimeStyles.AdjustToUniversal,
parsedDate) Then
Console.WriteLine($"{dateString} --> {parsedDate:g}")
Else
Console.WriteLine($"Cannot convert {dateString}")
End If
Next
' 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 является преобразование строкового представления из веб-службы в стандартном формате ISO 8601 . В следующем коде показана правильная строка формата для использования:
var iso8601String = "20080501T08:30:52Z";
DateTime dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
System.Globalization.CultureInfo.InvariantCulture);
Console.WriteLine($"{iso8601String} --> {dateISO8602:g}");
let iso8601String = "20080501T08:30:52Z"
let dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture)
printfn $"{iso8601String} --> {dateISO8602:g}"
Dim iso8601String As String = "20080501T08:30:52Z"
Dim dateISO8602 As DateTime = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ", CultureInfo.InvariantCulture)
Console.WriteLine($"{iso8601String} --> {dateISO8602:g}")
Если не удается проанализировать строку, методы Parse и ParseExact вызывают исключение. Методы TryParse и TryParseExact возвращают значение Boolean, указывающее, выполнено ли преобразование успешно или завершилось ошибкой. В сценариях, когда производительность важна, следует использовать методы TryParse или TryParseExact. Операция синтаксического анализа для строк даты и времени, как правило, имеет высокую скорость сбоя, и обработка исключений является дорогой. Используйте эти методы, если строки введены пользователями или поступают из неизвестного источника.
Для получения дополнительной информации об анализе значений даты и времени см. Синтаксический анализ строк даты и времени.
Значения даты и времени
Описания значений времени в типе DateTime часто выражаются с помощью стандарта UTC. Координированное универсальное время — это международно признанное имя среднего времени Гринвича (GMT). Координированное универсальное время — это время, измеряемое в нулевых градусах долготы, точка источника UTC. Летнее время неприменимо к UTC.
Локальное время относительно определенного часового пояса. Часовой пояс связан с смещением времени. Смещение часового пояса — это смещение часового пояса, измеряемого в часах с точки источника UTC. Кроме того, на локальное время по желанию может влиять переход на летнее время, который добавляет или вычитает корректировку временного интервала. Местное время вычисляется добавлением смещения часового пояса к UTC и при необходимости корректировкой на летнее время. Смещение часового пояса в точке источника UTC равно нулю.
Время UTC подходит для вычислений, сравнений и хранения дат и времени в файлах. Локальное время подходит для отображения в пользовательских интерфейсах классических приложений. Приложения с поддержкой часовых поясов (например, многие веб-приложения) также должны работать с рядом других часовых поясов.
Если свойство Kind объекта DateTime равно DateTimeKind.Unspecified, не указано, представлено ли время как локальное, время UTC или в другом часовом поясе.
Разрешение даты и времени
Примечание.
В качестве альтернативы выполнению арифметики даты и времени на значениях DateTime для измерения прошедшего времени, можно использовать класс Stopwatch.
Свойство Ticks выражает значения даты и времени в единицах одного десятимиллионого числа секунды. Свойство Millisecond возвращает тысячные доли секунды в формате даты и времени. Использование повторяющихся вызовов свойства DateTime.Now для измерения истекшего времени зависит от системных часов. Системные часы в системах Windows 7 и Windows 8 имеют разрешение примерно в 15 миллисекунд. Это разрешение влияет на небольшие интервалы времени менее 100 миллисекунд.
В следующем примере показана зависимость текущих значений даты и времени от разрешения системных часов. В примере внешний цикл повторяется 20 раз, а внутренний цикл служит для задержки внешнего цикла. Если значение счетчика внешнего цикла равно 10, вызов метода Thread.Sleep вводит пятимиллисекундную задержку. В следующем примере показано количество миллисекунд, возвращаемое свойством DateTime.Now.Milliseconds
, которое изменяется только после вызова Thread.Sleep.
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.
let mutable output = ""
for i = 0 to 20 do
output <- output + $"{DateTime.Now.Millisecond}\n"
// Introduce a delay loop.
for _ = 0 to 1000 do ()
if i = 10 then
output <- output + "Thread.Sleep called...\n"
System.Threading.Thread.Sleep 5
printfn $"{output}"
// Press "Run" to see the output.
Dim output As String = ""
For ctr As Integer = 0 To 20
output += Date.Now.Millisecond.ToString() + vbCrLf
' Introduce a delay loop.
For delay As Integer = 0 To 1000
Next
If ctr = 10 Then
output += "Thread.Sleep called..." + vbCrLf
Thread.Sleep(5)
End If
Next
Console.WriteLine(output)
' The example displays output like the following:
' 111
' 111
' 111
' 111
' 111
' 111
' 111
' 111
' 111
' 111
' 111
' Thread.Sleep called...
' 143
' 143
' 143
' 143
' 143
' 143
' 143
' 143
' 143
' 143
Операции DateTime
Вычисление, использующее структуру DateTime, например Add или Subtract, не изменяет значение структуры. Вместо этого вычисление возвращает новую DateTime структуру, значение которой является результатом вычисления.
Операции преобразования между часовыми поясами (например, между UTC и местным временем или между одним часовым поясом и другим) принимают во внимание переход на летнее время, но операции арифметики и сравнения этого не делают.
Структура DateTime сама предлагает ограниченную поддержку преобразования из одного часового пояса в другой. Метод ToLocalTime можно использовать для преобразования utc в местное время или использовать метод ToUniversalTime для преобразования из локального времени в utc. Однако полный набор методов преобразования часовых поясов доступен в классе TimeZoneInfo. Вы преобразуете время в любой из часовых поясов мира в любой другой часовой пояс с помощью этих методов.
Вычисления и сравнения объектов DateTime имеют смысл только в том случае, если объекты представляют время в одном часовом поясе. Для представления часового пояса значения TimeZoneInfo можно использовать объект DateTime, хотя они слабо связаны. Объект DateTime не имеет свойства, возвращающего объект, представляющий часовой пояс даты и времени. Свойство Kind указывает, представляет ли DateTime
значение UTC, локальное время или не указано. В приложении с поддержкой часового пояса необходимо полагаться на некоторый внешний механизм, чтобы определить часовой пояс, в котором был создан объект DateTime. Можно использовать структуру, которая упаковывает как значение DateTime, так и объект TimeZoneInfo, представляющий часовой пояс DateTime. Дополнительные сведения о том, как использовать UTC при вычислениях и сравнениях со значениями DateTime, см. в на странице "Выполнение арифметических операций с датами и временем".
Каждый элемент DateTime неявно использует григорианский календарь для выполнения своей операции. Исключения — это методы, которые неявно указывают календарь. К ним относятся конструкторы, которые указывают календарь и методы с параметром, производным от IFormatProvider, например System.Globalization.DateTimeFormatInfo.
Операции, выполняемые членами типа DateTime, учитывают такие детали, как високосные годы и количество дней в месяце.
Значения DateTime и календари
Библиотека классов .NET включает ряд классов календаря, все из которых являются производными от класса Calendar. В их число входят:
- Класс ChineseLunisolarCalendar.
- Класс EastAsianLunisolarCalendar.
- Класс GregorianCalendar.
- Класс HebrewCalendar.
- Класс HijriCalendar.
- Класс JapaneseCalendar.
- Класс JapaneseLunisolarCalendar.
- Класс JulianCalendar.
- Класс KoreanCalendar.
- Класс KoreanLunisolarCalendar.
- Класс PersianCalendar.
- Класс TaiwanCalendar.
- Класс TaiwanLunisolarCalendar.
- Класс ThaiBuddhistCalendar.
- Класс UmAlQuraCalendar.
Это важно
Эры в японских календарях основаны на царствии императора и поэтому, как ожидается, изменятся. Например, 1 мая 2019 г. отмечено начало эпохи Reiwa в JapaneseCalendar и JapaneseLunisolarCalendar. Такое изменение эпохи влияет на все приложения, использующие эти календари. Для получения дополнительной информации и определения влияния на ваши приложения см. статью Обработка новой эпохи в японском календаре в .NET. Сведения о тестировании ваших приложений на системах Windows для обеспечения их готовности к изменению эпохи см. в разделе Подготовка приложения к изменению японской эпохи. Функции в .NET, поддерживающие календари с несколькими эрами, и рекомендации по работе с календарями, поддерживающими несколько эпох, см. в разделе Работа с эрами.
Каждая культура использует календарь по умолчанию, определяемый его свойством CultureInfo.Calendar только для чтения. Каждая культура может поддерживать один или несколько календарей, определенных её свойством только для чтения CultureInfo.OptionalCalendars. Календарь, используемый определенным объектом 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
let thTH = System.Globalization.CultureInfo "th-TH"
let value = DateTime(2016, 5, 28)
printfn $"{value.ToString thTH}"
thTH.DateTimeFormat.Calendar <- System.Globalization.GregorianCalendar()
printfn $"{value.ToString thTH}"
// The example displays the following output:
// 28/5/2559 0:00:00
// 28/5/2016 0:00:00
Dim thTH As New CultureInfo("th-TH")
Dim value As New DateTime(2016, 5, 28)
Console.WriteLine(value.ToString(thTH))
thTH.DateTimeFormat.Calendar = New 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
let thTH = System.Globalization.CultureInfo "th-TH"
let value = DateTime.Parse("28/05/2559", thTH)
printfn $"{value.ToString thTH}"
thTH.DateTimeFormat.Calendar <- System.Globalization.GregorianCalendar()
printfn $"{value.ToString thTH}"
// The example displays the following output:
// 28/5/2559 0:00:00
// 28/5/2016 0:00:00
Private Sub ThaiBuddhistEraParse()
Dim thTH As New CultureInfo("th-TH")
Dim value As DateTime = DateTime.Parse("28/5/2559", thTH)
Console.WriteLine(value.ToString(thTH))
thTH.DateTimeFormat.Calendar = New GregorianCalendar()
Console.WriteLine(value.ToString(thTH))
' The example displays the following output:
' 28/5/2559 0:00:00
' 28/5/2016 0:00:00
End Sub
Вы создаете экземпляр значения DateTime с использованием элементов даты и времени (число года, месяца и дня) определенного календаря, вызывая конструктор DateTime, включающего параметр calendar
, в который передается объект Calendar, представляющий этот календарь. В следующем примере используются элементы даты и времени из календаря 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
let thTH = System.Globalization.CultureInfo "th-TH"
let dat = DateTime(2559, 5, 28, thTH.DateTimeFormat.Calendar)
printfn $"""Thai Buddhist era date: {dat.ToString("d", thTH)}"""
printfn $"Gregorian date: {dat:d}"
// The example displays the following output:
// Thai Buddhist Era Date: 28/5/2559
// Gregorian Date: 28/05/2016
Dim thTH As New CultureInfo("th-TH")
Dim dat As 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
DateTime конструкторы, не содержащие параметр calendar
, предполагают, что элементы даты и времени выражаются как единицы в григорианском календаре.
Все остальные 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
let thTH = System.Globalization.CultureInfo "th-TH"
let cal = thTH.DateTimeFormat.Calendar
let dat = DateTime(2559, 5, 28, cal)
printfn "Using the Thai Buddhist Era calendar:"
printfn $"""Date: {dat.ToString("d", thTH)}"""
printfn $"Year: {cal.GetYear dat}"
printfn $"Leap year: {cal.IsLeapYear(cal.GetYear dat)}\n"
printfn "Using the Gregorian calendar:"
printfn $"Date: {dat:d}"
printfn $"Year: {dat.Year}"
printfn $"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
Dim thTH As New CultureInfo("th-TH")
Dim cal As Calendar = thTH.DateTimeFormat.Calendar
Dim dat As 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))}")
Console.WriteLine()
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
let thTH = System.Globalization.CultureInfo "th-TH"
let thCalendar = thTH.DateTimeFormat.Calendar
let dat = DateTime(1395, 8, 18, thCalendar)
printfn "Using the Thai Buddhist Era calendar:"
printfn $"""Date: {dat.ToString("d", thTH)}"""
printfn $"Day of Week: {thCalendar.GetDayOfWeek dat}"
printfn $"Week of year: {thCalendar.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}\n"
let greg = System.Globalization.GregorianCalendar()
printfn "Using the Gregorian calendar:"
printfn $"Date: {dat:d}"
printfn $"Day of Week: {dat.DayOfWeek}"
printfn $"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
Dim thTH As New CultureInfo("th-TH")
Dim thCalendar As Calendar = thTH.DateTimeFormat.Calendar
Dim dat As 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, CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}")
Console.WriteLine()
Dim greg As Calendar = New 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, 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 можно сохранять следующим образом:
- Преобразуйте их в строки и сохраните строки.
- преобразовать их в 64-разрядные целые значения (значение свойства Ticks) и сохранить целые числа.
- Сериализуйте значения DateTime.
Необходимо убедиться, что подпрограмма, которая восстанавливает значения DateTime, не теряет данные или создает исключение независимо от выбранного метода. Значения DateTime должны быть обратимыми. То есть исходное значение и восстановленное значение должны совпадать. И если исходное значение DateTime представляет собой один момент времени, оно должно указывать на тот же момент времени, когда оно будет восстановлено.
Сохранение значений в виде строк
Чтобы успешно восстановить DateTime значения, которые сохраняются в виде строк, выполните следующие правила:
Сделайте те же предположения о культуроспецифическом форматировании при восстановлении строки так же, как и при сохранении. Чтобы убедиться, что строка может быть восстановлена в системе, текущая культура которой отличается от культурных настроек системы, на которой она была сохранена, вызовите перегрузку ToString, чтобы сохранить строку с помощью соглашений инвариантной культуры. Вызовите перегрузку функции Parse(String, IFormatProvider, DateTimeStyles) или TryParse(String, IFormatProvider, DateTimeStyles, DateTime), чтобы восстановить строку в соответствии с соглашениями инвариантной культуры. Никогда не используйте перегрузки ToString(), Parse(String)или TryParse(String, DateTime), которые используют соглашения текущей культуры.
Если дата представляет один момент времени, убедитесь, что она представляет тот же момент времени, когда он восстанавливается, даже в другом часовом поясе. Преобразуйте значение DateTime в координированное универсальное время (UTC) перед сохранением или использованием DateTimeOffset.
Наиболее распространенная ошибка при сохранении значений DateTime в виде строк заключается в том, чтобы полагаться на соглашения о форматировании по умолчанию или текущей культуры. Проблемы возникают, если текущая культура отличается при сохранении и восстановлении строк. В следующем примере показаны эти проблемы. Он сохраняет пять дат, используя текущие языковые и региональные стандарты форматирования, которые в данном случае соответствуют английскому (США). Он восстанавливает даты, используя форматы другой культуры, в данном случае — английской (Соединенное Королевство). Поскольку форматы в двух культурах различаются, две даты не могут быть воспроизведены, а оставшиеся три даты неправильно интерпретируются. Кроме того, если исходные значения даты и времени представляют отдельные моменты во времени, то восстановленное время неверно, так как сведения часового пояса теряются.
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...
let saveLocalDatesAsString () =
let dates =
[ DateTime(2014, 6, 14, 6, 32, 0)
DateTime(2014, 7, 10, 23, 49, 0)
DateTime(2015, 1, 10, 1, 16, 0)
DateTime(2014, 12, 20, 21, 45, 0)
DateTime(2014, 6, 2, 15, 14, 0) ]
printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
let output =
[ for date in dates do
printfn $"{date}"
string date ]
|> String.concat "|"
use sw = new StreamWriter(filenameTxt)
sw.Write output
printfn "Saved dates..."
let restoreLocalDatesFromString () =
TimeZoneInfo.ClearCachedData()
printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-GB"
use sr = new StreamReader(filenameTxt)
let inputValues =
sr.ReadToEnd().Split('|', StringSplitOptions.RemoveEmptyEntries)
printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
for inputValue in inputValues do
match DateTime.TryParse inputValue with
| true, dateValue ->
printfn $"'{inputValue}' --> {dateValue:f}"
| _ ->
printfn $"Cannot parse '{inputValue}'"
printfn "Restored dates..."
let persistAsLocalStrings () =
saveLocalDatesAsString ()
restoreLocalDatesFromString ()
// 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, выполните следующие действия.
- Если значения представляют отдельные моменты времени, преобразуйте их из локального времени в UTC, вызвав метод ToUniversalTime.
- Преобразуйте даты в их строковые представления, вызвав перегрузку ToString(String, IFormatProvider) или String.Format(IFormatProvider, String, Object[]). Используйте соглашения форматирования инвариантной культуры, указав CultureInfo.InvariantCulture в качестве аргумента
provider
. Определите, что значение должно иметь возможность двунаправленного преобразования, используя строку стандартного формата "O" или "R".
Чтобы восстановить сохраненные значения DateTime без потери данных, выполните следующие действия.
- Выполните разбор данных, вызвав перегрузку ParseExact или TryParseExact. Укажите CultureInfo.InvariantCulture в качестве аргумента
provider
и используйте ту же стандартную строку формата, которую вы использовали для аргументаformat
во время преобразования. Включите значение DateTimeStyles.RoundtripKind в аргументstyles
. - Если значения DateTime представляют отдельные моменты времени, вызовите метод 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...
let saveDatesAsInvariantStrings () =
let dates =
[ DateTime(2014, 6, 14, 6, 32, 0)
DateTime(2014, 7, 10, 23, 49, 0)
DateTime(2015, 1, 10, 1, 16, 0)
DateTime(2014, 12, 20, 21, 45, 0)
DateTime(2014, 6, 2, 15, 14, 0) ]
printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
let output =
[ for date in dates do
printfn $"{date:f}"
date.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) ]
|> String.concat "|"
use sw = new StreamWriter(filenameTxt)
sw.Write output
printfn "Saved dates..."
let restoreDatesAsInvariantStrings () =
TimeZoneInfo.ClearCachedData()
printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-GB"
use sr = new StreamReader(filenameTxt)
let inputValues =
sr.ReadToEnd().Split('|', StringSplitOptions.RemoveEmptyEntries)
printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
for inputValue in inputValues do
match DateTime.TryParseExact(inputValue, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind) with
| true, dateValue ->
printfn $"'{inputValue}' --> {dateValue.ToLocalTime():f}"
| _ ->
printfn $"Cannot parse '{inputValue}'"
printfn "Restored dates..."
let persistAsInvariantStrings () =
saveDatesAsInvariantStrings ()
restoreDatesAsInvariantStrings ()
// 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 в виде целого числа:
- Если значения DateTime представляют отдельные моменты во времени, преобразуйте их в формат UTC, вызвав метод ToUniversalTime.
- Извлеките количество тиков, представленных значением DateTime из его свойства Ticks.
Чтобы восстановить значение DateTime, которое было сохранено в виде целого числа:
- Создайте экземпляр нового объекта DateTime путем передачи значения Int64 конструктору DateTime(Int64).
- Если значение DateTime представляет один момент времени, преобразуйте его из UTC в местное время путем вызова метода ToLocalTime.
В следующем примере массив значений DateTime сохраняется в виде целых чисел в системе в часовом поясе США. Он производит восстановление на системе в часовой зоне UTC. Файл, содержащий целые числа, включает значение Int32, указывающее общее количество Int64 значений, которые немедленно следуют за ним.
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...
let saveDatesAsInts () =
let dates =
[ DateTime(2014, 6, 14, 6, 32, 0)
DateTime(2014, 7, 10, 23, 49, 0)
DateTime(2015, 1, 10, 1, 16, 0)
DateTime(2014, 12, 20, 21, 45, 0)
DateTime(2014, 6, 2, 15, 14, 0) ]
printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
let ticks =
[| for date in dates do
printfn $"{date:f}"
date.ToUniversalTime().Ticks |]
use fs = new FileStream(filenameInts, FileMode.Create)
use bw = new BinaryWriter(fs)
bw.Write ticks.Length
for tick in ticks do
bw.Write tick
printfn "Saved dates..."
let restoreDatesAsInts () =
TimeZoneInfo.ClearCachedData()
printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-GB"
use fs = new FileStream(filenameInts, FileMode.Open)
use br = new BinaryReader(fs)
try
let items = br.ReadInt32()
let dates =
[| for _ in 0..items do
let ticks = br.ReadInt64()
DateTime(ticks).ToLocalTime() |]
printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
for value in dates do
printfn $"{value:f}"
with
| :? EndOfStreamException ->
printfn "File corruption detected. Unable to restore data..."
| :? IOException ->
printfn "Unspecified I/O error. Unable to restore data..."
// Thrown during array initialization.
| :? OutOfMemoryException ->
printfn"File corruption detected. Unable to restore data..."
printfn "Restored dates..."
let persistAsIntegers () =
saveDatesAsInts ()
restoreDatesAsInts ()
// 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 данные сериализуются в определенном формате объекта. Объекты восстанавливаются в процессе десериализации. Формататор или сериализатор, например JsonSerializer или XmlSerializer, обрабатывает процесс сериализации и десериализации. Дополнительные сведения о сериализации и поддерживаемых в .NET типах сериализации см. в разделе Сериализация.
В следующем примере для сериализации и десериализации значений XmlSerializer используется класс DateTime. Эти значения представляют все дни високосного года в двадцать первом веке. Выходные данные представляют результат выполнения примера на системе с текущей локализацией, установленной на английский (Соединенное Королевство). Так как вы десериализировали сам объект 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
let persistAsXML () =
// Serialize the data.
let leapYears =
[| for year in 2000..4..2100 do
if DateTime.IsLeapYear year then
DateTime(year, 2, 29) |]
let serializer = XmlSerializer(leapYears.GetType())
use sw = new StreamWriter(filenameXml)
try
serializer.Serialize(sw, leapYears)
with :? InvalidOperationException as e ->
printfn $"{e.InnerException.Message}"
// Deserialize the data.
use fs = new FileStream(filenameXml, FileMode.Open)
let deserializedDates = serializer.Deserialize fs :?> DateTime []
// Display the dates.
printfn $"Leap year days from 2000-2100 on an {Thread.CurrentThread.CurrentCulture.Name} system:"
let mutable nItems = 0
for dat in deserializedDates do
printf $" {dat:d} "
nItems <- nItems + 1
if nItems % 5 = 0 then
printfn ""
// 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 представляет момент времени и выражается как локальное время, преобразуйте его из локального времени в utc, прежде чем сериализовать его путем вызова метода ToUniversalTime. После десериализации преобразуйте его из UTC в локальное время, вызвав метод ToLocalTime.
DateTime и TimeSpan
Типы значений DateTime и TimeSpan отличаются в том, что DateTime представляет мгновенное время, а TimeSpan представляет интервал времени. Чтобы получить объект типа DateTime, представляющий интервал времени между ними, можно вычесть один объект TimeSpan из другого. Или можно добавить положительный TimeSpan в текущую DateTime, чтобы получить значение DateTime, представляющее дату будущего.
Можно добавить или вычесть интервал времени из объекта DateTime. Интервалы времени могут быть отрицательными или положительными, и они могут быть выражены в единицах, таких как тик, секунды или как объект TimeSpan.
Сравнение на равенство с учетом допустимой погрешности
Сравнения равенства для значений DateTime точны. Чтобы считать равным, два значения должны быть выражены как одно и то же количество галок. Эта точность часто является ненужной или даже неправильной для многих приложений. Часто требуется проверить, ли объекты 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
let roughlyEquals (time: DateTime) (timeWithWindow: DateTime) windowInSeconds frequencyInSeconds =
let delta =
int64 (timeWithWindow - time).TotalSeconds % frequencyInSeconds
let delta = if delta > windowInSeconds then frequencyInSeconds - delta else delta
abs delta < windowInSeconds
let testRoughlyEquals () =
let window = 10
let window' = 10.
let freq = 60 * 60 * 2 // 2 hours
let d1 = DateTime.Now
let d2 = d1.AddSeconds(2. * window')
let d3 = d1.AddSeconds(-2. * window')
let d4 = d1.AddSeconds(window' / 2.)
let d5 = d1.AddSeconds(-window' / 2.)
let d6 = (d1.AddHours 2).AddSeconds(2. * window')
let d7 = (d1.AddHours 2).AddSeconds(-2. * window')
let d8 = (d1.AddHours 2).AddSeconds(window' / 2.)
let d9 = (d1.AddHours 2).AddSeconds(-window' / 2.)
printfn $"d1 ({d1}) ~= d1 ({d1}): {roughlyEquals d1 d1 window freq}"
printfn $"d1 ({d1}) ~= d2 ({d2}): {roughlyEquals d1 d2 window freq}"
printfn $"d1 ({d1}) ~= d3 ({d3}): {roughlyEquals d1 d3 window freq}"
printfn $"d1 ({d1}) ~= d4 ({d4}): {roughlyEquals d1 d4 window freq}"
printfn $"d1 ({d1}) ~= d5 ({d5}): {roughlyEquals d1 d5 window freq}"
printfn $"d1 ({d1}) ~= d6 ({d6}): {roughlyEquals d1 d6 window freq}"
printfn $"d1 ({d1}) ~= d7 ({d7}): {roughlyEquals d1 d7 window freq}"
printfn $"d1 ({d1}) ~= d8 ({d8}): {roughlyEquals d1 d8 window freq}"
printfn $"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
Public Shared Function RoughlyEquals(time As DateTime, timeWithWindow As DateTime,
windowInSeconds As Integer,
frequencyInSeconds As Integer) As Boolean
Dim delta As Long = (timeWithWindow.Subtract(time)).TotalSeconds _
Mod frequencyInSeconds
If delta > windowInSeconds Then
delta = frequencyInSeconds - delta
End If
Return Math.Abs(delta) < windowInSeconds
End Function
Public Shared Sub TestRoughlyEquals()
Dim window As Integer = 10
Dim freq As Integer = 60 * 60 * 2 ' 2 hours;
Dim d1 As DateTime = DateTime.Now
Dim d2 As DateTime = d1.AddSeconds(2 * window)
Dim d3 As DateTime = d1.AddSeconds(-2 * window)
Dim d4 As DateTime = d1.AddSeconds(window / 2)
Dim d5 As DateTime = d1.AddSeconds(-window / 2)
Dim d6 As DateTime = d1.AddHours(2).AddSeconds(2 * window)
Dim d7 As DateTime = d1.AddHours(2).AddSeconds(-2 * window)
Dim d8 As DateTime = d1.AddHours(2).AddSeconds(window / 2)
Dim d9 As DateTime = 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)}")
End Sub
' 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
Значение DateTime, которое передается в COM-приложение, а затем возвращается в управляемое приложение, называется двойной передачей. Однако значение DateTime, указывающее только время, не возвращается в исходное состояние, как ожидалось.
Если вы указываете только время, например, 15:00, то окончательная дата и время устанавливаются как 30 декабря 1899 н.э. в 15:00, а не 1 января 0001 н.э. в 15:00. .NET и COM предполагают дату по умолчанию, если указано только время. Однако система COM предполагает базовую дату 30 декабря 1899 C.E., а .NET предполагает базовую дату 1 января 0001 C.E.
Когда передается только время из .NET в COM, выполняется специальная обработка, которая преобразует время в формат, используемый COM. Когда передается лишь время из COM в .NET, специальная обработка не выполняется, так как это повреждает действительные даты и время на или до 30 декабря 1899 года. Если дата начинает свой круговой поход с COM, .NET и COM сохраняют дату.
Поведение .NET и COM означает, что если ваше приложение выполняет преобразования туда и обратно DateTime, указывающий только время, ваше приложение должно помнить об изменении или игнорировании ошибочной даты из конечного объекта DateTime.