1. Введение
Раньше в C# не было отдельного типа только для даты или только для времени. Поэтому, даже если вам нужно было хранить только дату — например, день рождения — приходилось использовать DateTime и добавлять "время по умолчанию". Старый способ хранения только даты через DateTime:
DateTime birthday = new DateTime(1985, 4, 20); // 20 апреля 1985 года, 00:00:00
Но это неудобно. Вы вроде бы хотите просто дату, а получаете ещё и время — пусть и нулевое. Это может запутать: например, при сравнении дат программа может учитывать и время, и вы получите неожиданные результаты.
Та же история и с обратной ситуацией: если вы работаете только со временем (например, график работы с 08:00 до 17:00), вам всё равно нужно было "придумать" какую-то дату, хотя она вообще не важна.
Теперь в .NET есть специальные типы DateOnly и TimeOnly, которые избавляют от этой путаницы.
Новые полезные типы DateOnly и TimeOnly
- DateOnly — только календарная дата, без времени суток и без информации о часовом поясе.
- TimeOnly — только время суток, без года, месяца, дня и, опять же, без часового пояса.
Таблица сравнения типов времени
| Тип | Дата | Время | Часовой пояс | Для чего используется? |
|---|---|---|---|---|
|
✅ | ✅ | 🚫 | Почти всё подряд (но не всегда удобно и безопасно) |
|
✅ | ✅ | ✅ | Когда нужен и момент времени, и часовой пояс |
|
✅ | 🚫 | 🚫 | Дни рождения, даты без времени |
|
🚫 | ✅ | 🚫 | Часы работы, расписания, интервалы в течение дня |
2. Работа с DateOnly
Объявление и создание
Создать объект DateOnly — как завести новую привычку: просто и быстро! Например:
// Год, месяц, день
DateOnly birthday = new DateOnly(1985, 4, 20);
Можно использовать DateOnly.FromDateTime, если у вас уже есть объект DateTime:
DateTime now = DateTime.Now;
DateOnly today = DateOnly.FromDateTime(now);
// теперь today содержит только дату, время отброшено
Основные свойства и методы
- Year, Month, Day — привычно, как у DateTime.
- .ToString() — форматирует дату, можно задавать свой формат.
Console.WriteLine($"Дата рождения: {birthday.Year} год, {birthday.Month} месяц, {birthday.Day} число.");
Console.WriteLine(today.ToString("dd.MM.yyyy")); // Например, 30.07.2024
Арифметика дат
Можно легко добавлять дни/месяцы/годы:
DateOnly tomorrow = today.AddDays(1);
DateOnly nextMonth = today.AddMonths(1);
Попробуйте в вашем основном приложении заменить поля с типом DateTime, которые хранят только дату, на DateOnly — вы окажетесь на шаг ближе к современному .NET!
Сравнение дат
Работает сравнение через <, >, ==:
if (birthday < today)
Console.WriteLine("День рождения уже был в этом году или давно :)");
Ошибок с лишними миллисекундами и минутами уже не будет.
Получение сегодняшнего дня
DateOnly currentDate = DateOnly.FromDateTime(DateTime.Now);
3. Работа с TimeOnly
Теперь займёмся временем без даты — ведь кто из программистов не сталкивался с расписаниями обедов?
Создание TimeOnly
TimeOnly startWork = new TimeOnly(9, 0); // 09:00
TimeOnly endWork = new TimeOnly(17, 30); // 17:30
Можем получить только часы, минуты, секунды:
Console.WriteLine($"Рабочий день: с {startWork.Hour}:{startWork.Minute:D2} до {endWork.Hour}:{endWork.Minute:D2}");
Получить время из DateTime
DateTime now = DateTime.Now;
TimeOnly currentTime = TimeOnly.FromDateTime(now);
Console.WriteLine($"Сейчас {currentTime}");
Арифметика времени
TimeOnly breakStart = startWork.AddHours(4); // перерыв через 4 часа, т.е. в 13:00
TimeOnly breakEnd = breakStart.AddMinutes(30); // 30 минут обед
Сравнения и проверки
if (currentTime >= startWork && currentTime <= endWork)
Console.WriteLine("Время работать :)");
else
Console.WriteLine("Можно отдыхать.");
4. Взаимодействие с другими типами
Преобразование между DateOnly, TimeOnly и DateTime
Иногда нужно снова получить DateTime (например, для хранения в старой базе или для совместимости):
DateOnly datePart = new DateOnly(2024, 7, 30);
TimeOnly timePart = new TimeOnly(14, 15);
DateTime datetime = datePart.ToDateTime(timePart); // 2024-07-30 14:15:00
И наоборот:
DateTime dt = DateTime.Now;
DateOnly justDate = DateOnly.FromDateTime(dt);
TimeOnly justTime = TimeOnly.FromDateTime(dt);
Важные особенности и типичные ошибки
- Если вы попробуете распарсить только дату или только время с помощью старых методов вроде DateTime.Parse(), скорее всего получите ошибку или не то, что ожидали. Для таких случаев есть специальные методы: используйте DateOnly.Parse() и TimeOnly.Parse() — они знают, как обращаться с "обрезанными" значениями.
- Важно понимать: DateOnly и TimeOnly не имеют ни малейшего представления о временных зонах. Это просто дата или просто время — без связи с часовым поясом. Если нужно учитывать зоны, храните эту информацию отдельно.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ