C#: дата и время

Для работы с датой и временем в пространстве имен System предусмотрено три неизменяемых структуры: DateTime, DateTimeOffset и TimeSpan.

TimeSpan

Структура TimeSpan представляет временной интервал или время суток. В последнем случае это время (без даты) прошедшее с полуночи (без учет переходов на летнее время). Минимально значение для TimeSpan — 100 наносекунд, максимальное — примерно 10 миллионов дней (значение может быть и положительным, и отрицательным).

Создать экземпляр TimeSpan можно с помощью конструктора, вызвав один из статических методов From..., либо путем вычитания одного экземпляра DateTime из другого.

Предусмотрено 4 перегруженных конструктора:

Статические методы From... более удобны когда нужно указать интервал в каких-то одних единицах (минутах, секундах):

Пример:

TimeSpan перегружает операторы <, >, + и -:

TimeSpan содержит свойства Days, Hours, MinutesSeconds и Milliseconds, возвращающие соответствующие целочисленные значения, а также аналогичные свойства Total..., возвращающие значения типа double:

Статический метод Parse является противоположностью ToString, преобразуя строку в TimeSpan. Метод TryParse делает тоже самое, но в случае неудачи возвращает false вместо генерации исключения.

Значением по умолчанию для TimeSpan является TimeSpan.Zero.

DateTime и DateTimeOffset

DateTime и DateTimeOffset — это неизменяемые структуры для представления даты и времени. Поддерживаемый диапазон лет — от 0001 до 9999, а минимальный шаг (tick) — 100 наносекунд.

Структуры отличаются по своему внутреннему строению и тем, как они обрабатывают часовые пояса. DateTime состоит из двух порций информации:

  • 62-битное число, указывающее количество tick, прошедшее с 1/1/001
  • 2-битное значение enum — флаг DateTimeKind с тремя состояниями, который указывает, относительно чего берется DateTime:
    • Local — местное время на текущем компьютере
    • Utc — UTC (современный эквивалент Гринвича)
    • Unspecified — не определено — принимается по умолчанию и означает, что DateTime не зависит от часового пояса

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

Структура DateTimeOffset внутри содержит:

  • поле DateTime, значение которого всегда представлено относительно UTC
  • 16-битное целочисленное поле Offset (тип TimeSpan), выражающее смещение относительно UTC в минутах

Во время сравнения DateTimeOffset сравнивает только поле DateTime (которое в UTC), Offset игнорируется. Таким образом DateTimeOffset считает два значения равными, если они ссылаются на одну и туже точку во времени.

Исходя из этого, DateTime считает следующие два значения различными, а DateTimeOffset — равными:

Создание экземпляра DateTime 

DateTime определяет два конструктора, которые принимают целочисленные значения для года, месяца и дня, а также дополнительно — для часов, минут, секунд и миллисекунд:

Если указывается только дата, время неявно устанавливается в полночь (0:00). Также конструктор DateTime позволяет задать указанный выше флаг DateTimeKind:

Перегруженный конструктор DateTime может принимать объект Calendar (System.Globalization), позволяя задать используемый календарь:

По умолчанию используется григорианский календарь. Для выполнения вычислений с использованием другого календаря необходимо использовать соответствующие методы подкласс Calendar.

Создать экземпляр DateTime можно также передав конструктору единственный параметр ticks типа long, соответствующий количеству 100-наносекундных интервалов, прошедших от полуночи 01/01/0001.

Экземпляр DateTime можно создать с помощью статических методов FromFileTime и FromFileTimeUtc, преобразующих время файлов Windows (тип long), а также с помощью статического метода FromOADate, преобразующего даты и время автоматизации OLE (тип double).

С помощью статического метода SpecifyKind можно создать экземпляр DateTime, который будет отличаться от другого только значением DateTimeKind:

Для создания объекта DateTime из строки нужно воспользоваться статическим методом Parse или ParseExact. Оба метода могут дополнительно принимать флаги и поставщики форматов, а ParseExact также может принимать форматную строку.

Создание экземпляра DateTimeOffset

DateTimeOffset имеет похожий набор конструкторов, но им обязательно также нужно передавать смещение UTC в виде TimeSpan:

Значение TimeSpan должно составлять целое количество минут, иначе будет выброшено исключение.

DateTimeOffset также имеет конструкторы, которые принимают объект Calendar, значение ticks типа long, а также статические методы Parse и ParseExact, принимающие строку.

Экземпляр DateTimeOffset можно также создать из существующего экземпляра DateTime либо с помощью конструктора, либо с помощью неявного приведения:

Если смещение не указано, он выводится автоматически по следующим правилам:

  • если свойство DateTimeKind объекта DateTime равно Utc, смещение принимается равным нулю
  • если свойство DateTimeKind объекта DateTime равно Local или Unspecified (по умолчанию), смещение берется из текущего часового пояса

DateTimeOffset также может быть преобразован в DateTime с помощью одного из трех свойств:

  • UtcDateTime возвращает экземпляр DateTime как время UTC (без смещения)
  • LocalDateTime возвращает экземпляр DateTime в текущем часовом поясе
  • DateTime возвращает экземпляр DateTime в часовом поясе, переданном в качестве аргумента (свойство Kind устанавливается равным Unspecified)

Текущая дата и время

Обе структуры имеют статические свойство Now, которое возвращает текущую дату и время:

Статическое свойство UtcNow возвращает текущую дату и время в UTC:

DateTime содержит также статическое свойство Today, возвращающее текущую дату (без времени):

Манипулирование датой и временем

Обе структуры имеют схожий набор свойств, возвращающих элементы даты и времени:

DateTimeOffset также содержит свойство Offset, возвращающее TimeSpan, а DateTime — свойство Kind, возвращающее значение DateTimeKind.

Обе структуры содержат ряд методов для выполнения вычислений (большинство принимают аргументы типа double или int):

  • AddYears
  • AddMonths
  • AddDays
  • AddHours
  • AddMinutes
  • AddSeconds
  • AddMilliseconds
  • AddTicks

Эти методы возвращают новый экземпляр DateTime или DateTimeOffset и учитывают високосный год. Для вычитания можно передавать отрицательное значение.

Метод Add добавляет TimeSpan к DateTime или DateTimeOffset. Оператор + выполняет тоже самое:

Можно также вычитать TimeSpan из DateTime/DateTimeOffset и вычитать один экземпляр
DateTime/DateTimeOffset из другого, в последнем случае будет возвращен TimeSpan:

Форматирование даты и времени

Вызов ToString на объекте DateTime форматирует результат в виде краткой даты (только числа), за которой следует полное время (включая секунды):

По умолчанию панель управления ОС определяет такие вещи, как порядок следования даты, месяца и года, должны ли использоваться ведущие нули, формат времени (12 или 24 часа) и др.

Вызов ToString на объекте DateTimeOffset делает тоже самое, но добавляет еще и смещение:

Методы ToShortDateString и ToLongDateString возвращают только дату в коротком или длинном формате. Формат длинной даты также определяется в панели управления. Методы ToShortTimeString и ToLongTimeString возвращают только время (ToShortTimeString без секунд).

Метод ToString перегружен для приема форматной строки и поставщиков, позволяя указывать широкий диапазон опций и управлять применением региональных настроек.

ToUniversalTime и ToLocalTime

Экземплярные методы ToUniversalTime и ToLocalTime структуры DateTime выполняют преобразование в универсальное (UTC) или местное время. Они применяют текущие настройки часового пояса компьютера и возвращают новый экземпляр DateTime со значением DateTimeKind, равным Utc или Local:

Экземплярные методы ToUniversalTime и ToLocalTime структуры DateTimeOffset возвращают новый экземпляр, представляющий тот же самый момент времени, но в UTC или местном времени. В отличие от аналогичных методов DateTime, эти методы не оказывают влияния на лежащее в основе значение даты и времени, а изменяют только смещение:

С помощью метода EqualsExact можно включить в сравнение поле Offset:

TimeZone и TimeZoneInfo

Классы TimeZone и TimeZoneInfo предоставляют информацию, касающуюся названий часовых поясов, смещений UTC и правил перехода на зимнее время. TimeZone позволяет обратиться только к текущему местному часовому поясу, а TimeZoneInfo обеспечивает доступ к часовым поясам во всем мире.

TimeZone

Статический метод TimeZone.CurrentTimeZone возвращает экземпляр TimeZone на основе текущих местных настроек:

Метод IsDaylightSavingTime возвращает true, если переданный ему объект DateTime относится к зимнему времени, и false — если к летнему:

Метод GetUtcOffset возвращает смещение относительно UTC для переданного ему объекта DateTime:

Метод GetDaylightChanges возвращает специфическую информацию о зимнем времени для заданного года:

TimeZoneInfo

Класс TimeZoneInfo работает аналогичным образом. Статический класс TimeZoneInfo.Local возвращает экземпляр TimeZoneInfo для текущего местного часового пояса:

Класс TimeZoneInfo также содержит методы IsDaylightSavingTime и GetUtcOffset, но в отличие от одноименных методов класс TimeZone они могут принимать как объекты типа DateTime так и объекты DateTimeOffset.

Вызвав метод FindSystemTimeZoneById с идентификатором часового пояса (Id), можно получить объект TimeZoneInfo для любого часового пояса в мире.

Свойство Id соответствует значению передаваемому методу FindSystemTimeZoneById. Статический метод GetSystemTimeZones возвращает все часовые пояса мира, соответственно можно вывести список всех доступных Id часовых поясов:

С помощью статического метода TimeZoneInfo.CreateCustomTimeZone можно создать свой специфический часовой пояс, передав методу все данные о часовом поясе. После создания экземпляра изменить его свойства уже нельзя, т.к. TimeZoneInfo является неизменяемым.

С помощью экземплярного метода ToSerializedString можно сериализовать часовой пояс в читабельную строку, а с помощью статического метода TimeZoneInfo.FromSerializedString — десериализовать ее.

Статический метод ConvertTime преобразует DateTime или DateTimeOffset из одного часового пояса в другой, а методы ConvertTimeFromUtc и ConvertTimeToUtc преобразуют непосредственно в или из UTC.

Для работы с зимнем временем класс TimeZoneInfo предлагает следующие методы:

  • IsInvalidTime — возвращает true, если DateTime находится в пределах часа, который будет пропущен, когда часы переводятся вперед
  • IsAmbiguousTime — возвращает true, если DateTime или DateTimeOffset находится в пределах часа, который будет повторен, когда часы переводятся назад
  • GetAmbiguousTimeOffsets — возвращает массив из TimeSpan, представляющий допустимые варианты смещения для DateTime или DateTimeOffset, находящихся в пределах часа, повторяющегося при переводе часов назад.

В отличие от TimeZone, из TimeZoneInfo нельзя получить напрямую даты, указывающие начало и конец зимнего времени. Вместо этого нужно вызывать метод GetAdjustmentRules, который возвращает список правил перехода на зимнее время, применяемых ко всем годам. Каждое правило — объект типа TimeZoneInfo.AdjustmentRule — имеет свойства DateStart и DateEnd, указывающие диапазон дат, в пределах которого это правило допустимо:

Например в западной Австралии переход на зимнее время впервые был введен в 2006 г. в межсезонье, поэтому для первого года будет отдельное правило, а всего их будет два:

Каждый экземпляр TimeZoneInfo.AdjustmentRule имеет свойство DaylightDelta типа TimeSpan — время, необходимое для перехода на зимнее время в данном часовом поясе (смещение для зимнего времени), как правило это один час.

Также AdjustmentRule содержит свойства DaylightTransitionStart и DaylightTransitionEnd, возвращающие тип TimeZoneInfo.TransitionTime, включающий следующие свойства:

Правило может выражать как фиксированную дату (например, 5 марта 2:00), так и плавающую (например, последнее воскресенье марта). Свойство IsFixedDateRule возвращает true если дата фиксированная, и fasle если дата плавающая. Фиксированная дата задается свойствами Day, Month и TimeOfDay, а плавающая — DayOfWeek, Week, Month и TimeOfDay.

Преобразование даты в строку

Объекты DateTime и DateTimeOffset могут быть преобразованы в строку с помощью экземплярного метода ToString. В качестве дополнительного параметра метод может принимать форматные строки. Подробно этот метод и форматные строки рассмотрены в разделе, посвященном форматированию и преобразованию строк. Ниже будут перечислены стандартные и специальные форматные строки для типов DateTime и DateTimeOffset.

Стандартные форматные строки для даты, чувствительные к культуре

Форматная строкаЗначениеПример
dКраткая дата01/02/2000
DПолная датаSunday, 02 January 2000
tКраткое время17:18
TПолное время17:18:19
fПолная дата+краткое времяSunday, 02 January 2000 17:18
FПолная дата+полное времяSunday, 02 January 2000 17:18:19
gКраткая дата+краткое время01/02/2000 17:18
G (по умолчанию)Краткая дата+полное время01/02/2000 17:18:19
m, MМесяц и деньJanuary 02
y, YГод и месяц2000 January

Стандартные форматные строки для даты, не чувствительные к культуре

Форматная строкаЗначениеПримерПримечание
oВозможность кругового преобразования2000-01-02T17:18:19.0000000Если DateTimeKind не является Unspecified, будет присоединяться информация о часовом поясе
r, RСтандарт RFC 1123Sun, 02 Jan 2000 17:18:19 GMTНе преобразованное в UTC
sСортируемое, ISO 86012000-01-02T17:18:19Совместимо с текстовой сортировкой
uУниверсально сортируемое2000-01-02 17:18:19ZСовместимо с текстовой сортировкой, не преобразованное в UTC
UUTCSunday, 02 January 2000 17:18:19Преобразованная в UTC

Специальные форматные строки для даты и времени

СимволОписаниеПример
dДень месяца в виде числа (1-31), одна цифра не дополняется нулем

6/1/2009 1:45:30 PM -> 1
6/15/2009 1:45:30 PM -> 15

ddДень месяца в виде числа (01-31), одна цифра дополняется нулем

6/1/2009 1:45:30 PM -> 01
6/15/2009 1:45:30 PM -> 15

dddСокращенное название дня недели

6/15/2009 1:45:30 PM -> Mon (en-US)
6/15/2009 1:45:30 PM -> Пн (ru-RU)
6/15/2009 1:45:30 PM -> lun. (fr-FR)

ddddПолное название дня недели

6/15/2009 1:45:30 PM -> Monday (en-US)
6/15/2009 1:45:30 PM -> понедельник (ru-RU)
6/15/2009 1:45:30 PM -> lundi (fr-FR)

f — fffffffДесятые — десятимиллионные доли секунды6/15/2009 13:45:30.617 -> 6 (f)
6/15/2009 13:45:30.0001150 -> 0001150 (fffffff)
F — FFFFFFFТоже самое, что и предыдущее, но если соотвествующее значение равно 0, то не выводится ничего

6/15/2009 13:45:30.617 -> 6
6/15/2009 13:45:30.050 -> (нет вывода)

g, ggПериод или эра6/15/2009 1:45:30 PM -> A.D.
hЧас в 12-часовом формате от 1 до 126/15/2009 1:45:30 AM -> 1
6/15/2009 1:45:30 PM -> 1
hhЧас в 12-часовом формате от 01 до 12

6/15/2009 1:45:30 AM -> 01
6/15/2009 1:45:30 PM -> 01

HЧас в 24-часовом формате от 0 до 23

6/15/2009 1:45:30 AM -> 1
6/15/2009 1:45:30 PM -> 13

HHЧас в 24-часовом формате от 00 до 23

6/15/2009 1:45:30 AM -> 01
6/15/2009 1:45:30 PM -> 13

KДанные о часовом поясеСо значениями DateTime:
6/15/2009 1:45:30 PM, Kind Unspecified ->
6/15/2009 1:45:30 PM, Kind Utc -> Z
6/15/2009 1:45:30 PM, Kind Local -> -07:00 (зависит от настроек локального компьютера)
Со значениями DateTimeOffset:
6/15/2009 1:45:30 AM -07:00 —> -07:00
6/15/2009 8:45:30 AM +00:00 —> +00:00
mМинуты, в диапазоне от 0 до 596/15/2009 1:09:30 AM -> 9
mmМинуты, в диапазоне от 00 до 596/15/2009 1:09:30 AM -> 09
MМесяц, в диапазоне от 1 до 126/15/2009 1:45:30 PM -> 6
MMМесяц, в диапазоне от 01 до 126/15/2009 1:45:30 PM -> 06
MMMСокращенное название месяца6/15/2009 1:45:30 PM -> Jun (en-US)
MMMMПолное название месяца6/15/2009 1:45:30 PM -> June (en-US)
sСекунды, в диапазоне от 0 до 596/15/2009 1:45:09 PM -> 9
ssСекунды, в диапазоне от 00 до 596/15/2009 1:45:09 PM -> 09
tПервый символ указателя AM/PM6/15/2009 1:45:30 PM -> P (en-US)
6/15/2009 1:45:30 PM -> (fr-FR)
ttУказатель AM/PM6/15/2009 1:45:30 PM -> PM (en-US)
6/15/2009 1:45:30 PM -> (fr-FR)
yГод, в диапазоне от 0 до 99

1/1/1900 12:00:00 AM -> 0
6/15/2009 1:45:30 PM -> 9

yyГод, в диапазоне от 00 до 99

1/1/1900 12:00:00 AM -> 00
6/15/2009 1:45:30 PM -> 09

yyyГод в виде как минимум трех цифр1/1/0001 12:00:00 AM -> 001
6/15/2009 1:45:30 PM -> 2009
yyyyГод в виде четырехзначного числа1/1/0001 12:00:00 AM -> 0001
6/15/2009 1:45:30 PM -> 2009
yyyyyГод в виде пятизначного числа

1/1/0001 12:00:00 AM -> 00001
6/15/2009 1:45:30 PM -> 02009

zЧасовой сдвиг от времени в формате UTC, без нулей в начале

6/15/2009 1:45:30 PM -07:00 -> -7

zzЧасовой сдвиг от времени в формате UTC с нулями в начале для значений из одной цифры6/15/2009 1:45:30 PM -07:00 -> -07
zzzСдвиг в часах и минутах от времени в формате UTC6/15/2009 1:45:30 PM -07:00 -> -07:00
:Разделитель компонентов времени

6/15/2009 1:45:30 PM -> : (en-US)
6/15/2009 1:45:30 PM -> . (it-IT)

/Разделитель компонентов даты

6/15/2009 1:45:30 PM -> / (en-US)
6/15/2009 1:45:30 PM -> — (ar-DZ)
6/15/2009 1:45:30 PM -> . (tr-TR)

%Задает следующий символ в качестве настраиваемого описателя формата6/15/2009 1:45:30 PM (%h) -> 1
\Экранирующий символ6/15/2009 1:45:30 PM (h \h) -> 1 h
любой другой символСимвол копируется в результирующую строку без изменений6/15/2009 1:45:30 AM (arr hh:mm t) -> arr 01:45 A
строка с любыми символами в (двойных/одинарных) кавычкахБуквенный разделитель строк

6/15/2009 1:45:30 PM («arr:» h:m t) -> arr: 1:45 P
6/15/2009 1:45:30 PM (‘arr:’ h:m t) -> arr: 1:45 P

Преобразование строки в дату/время, DateTimeStyles

Преобразование строки в объекты DateTime или DateTimeOffset можно осуществить с помощью статических методов Parse и TryParse. Подробно эти методы рассмотрены в разделе, посвященном форматированию и преобразованию строк.

Оба метода могут принимать enum DateTimeStyles, определяющий как строка читается при преобразовании в тип даты и времени. Его членами являются:

  • None — стандартное значение, запрещает наличие во входной строке дополнительных пробельных символов
  • AllowLeadingWhite — допускает в начале входной строки дополнительные пробелы
  • AllowTrailingWhite — допускает в конце входной строки дополнительные пробелы
  • AllowInnerWhite — допускает внутри входной строки дополнительные пробелы
  • AssumeLocal — если входная строка не имеет суффикса часового пояса, дает указание использовать локальное значение
  • AssumeUniversal если входная строка не имеет суффикса часового пояса, дает указание использовать UTC
  • AdjustToUniversal — учитывает суффиксы часовых поясов во входной строке, но затем выполняет преобразование в UTC с использованием текущих региональных настроек
  • NoCurrentDateDefault — при разборе строки, содержащей время без даты, по умолчанию принимается сегодняшняя дата, но данный флаг дает указание в качестве даты использовать 01/01/0001
  • RoundTripKind
  • AllowWhiteSpaces — составной член, равен AllowLeadingWhite | AllowTrailingWhite | AllowInnerWhite

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *