1. Основные задачи при работе с датой и временем
Работа с датами и временем часто вызывает легкое (а иногда и не очень легкое) чувство паники даже у опытных разработчиков. Придётся сравнивать даты, вычислять интервалы, добавлять или вычитать дни/месяцы/годы, вычислять возраст, определять день недели и многое другое.
Всё это — типичные задачи для трекеров задач и календарей, учёта абонементов или подписок, финансовых расчётов, статистических отчётов, и, конечно, для задач на собеседованиях (например, "вычислить количество рабочих дней между двумя датами").
В C# и .NET для этих задач есть встроенные классы и методы. А главное — большинство вычислений делается через объектно-ориентированный, максимально безопасный и понятный API.
2. Структура TimeSpan — измеряем интервалы времени
Всё начинается с структуры TimeSpan. Это "кусочек" времени: например, 5 дней, 3 часа, 7 минут и 21 секунда.
Как создать TimeSpan?
Можно "вычесть" две даты, можно создать явно:
// Разница между двумя датами всегда TimeSpan!
DateTime start = new DateTime(2025, 5, 1, 7, 0, 0);
DateTime end = new DateTime(2025, 5, 2, 11, 30, 0);
TimeSpan duration = end - start; // Полная магия!
Console.WriteLine(duration); // 1.04:30:00 (1 день, 4 часа, 30 минут)
Можно явно создать TimeSpan через параметры конструктора:
TimeSpan span = new TimeSpan(2, 14, 18, 0); // 2 дня, 14 часов, 18 минут, 0 секунд
Console.WriteLine(span); // 2.14:18:00
Альтернативный способ создания — через статические методы, которые часто более читаемы:
TimeSpan fiveMinutes = TimeSpan.FromMinutes(5);
TimeSpan twoHours = TimeSpan.FromHours(2);
TimeSpan oneWeek = TimeSpan.FromDays(7);
Какие свойства есть у TimeSpan?
| Свойство | Описание |
|---|---|
|
Целое число дней |
|
Часовая часть |
|
Минутная часть |
|
Секундная часть |
|
Время в днях (дробное) |
|
Время в часах (дробное) |
|
Время в минутах (дробное) |
|
Время в секундах (дробное) |
Console.WriteLine($"Дней: {duration.Days}, Всего часов: {duration.TotalHours}");
Как добавить/вычесть TimeSpan из даты?
DateTime now = DateTime.Now;
DateTime future = now.Add(duration); // Добавили duration к now
DateTime past = now.Subtract(TimeSpan.FromDays(10)); // Минус 10 дней
Console.WriteLine(future);
Console.WriteLine(past);
3. Калькулятор дат: вычисляем разницу между датами
Навык, который пригодится примерно всегда. Например, кто-то хочет знать, сколько осталось до отпуска, а кто-то — когда заканчивается бесплатный период.
DateTime today = DateTime.Today;
DateTime vacation = new DateTime(2025, 8, 1);
TimeSpan untilVacation = vacation - today;
Console.WriteLine($"До отпуска осталось {untilVacation.Days} дней!");
Обратите внимание: если в вычитании участвуют только "даты" без времени (через DateTime.Date или DateTime.Today), то результат всегда целое число дней. А если хоть одна дата содержит время, разница — дробная.
int days = (vacation - today).TotalDays; // Ошибка компиляции! TotalDays — double
Если нужно целое число — используем .Days или приводим к целому типу через (int)TotalDays.
4. Добавление и вычитание времени: методы AddDays, AddMonths, AddHours, ...
C# не требует ручного подсчёта дней в каждом месяце, високосных лет и прочей боли. Просто используем:
DateTime orderDate = new DateTime(2024, 4, 20);
DateTime deliveryDate = orderDate.AddDays(14); // Через 2 недели
Console.WriteLine($"Товар будет доставлен {deliveryDate.ToShortDateString()}");
| Метод | Что добавляет (или вычитает при отрицательном числе) |
|---|---|
|
Дни (поддержка дробей, например 1,5 дня) |
|
Месяцы (автоматически учитывает длину месяца) |
|
Годы (даже с учётом високосных) |
|
Часы |
|
Минуты |
|
Секунды |
DateTime birthday = new DateTime(2000, 2, 29);
DateTime nextYear = birthday.AddYears(1); // 2001-02-28 (не 29-го, ибо 2001 не високосный)
Console.WriteLine(nextYear.ToShortDateString()); // 28.02.2001
Не забывайте: все методы возвращают новый экземпляр даты, исходная дата не меняется!
var dt = DateTime.Now;
dt.AddDays(5); // Это НЕ изменит dt!
dt = dt.AddDays(5); // Теперь изменится
5. Вспомогательные методы для вычислений
Расчёт дня недели
В большинстве случаев можно использовать свойство .DayOfWeek:
DateTime examDate = new DateTime(2025, 6, 19);
DayOfWeek day = examDate.DayOfWeek;
Console.WriteLine(day); // Wednesday
Можно привести к целому числу:
int number = (int)day; // Sunday == 0, Monday == 1, и так далее
Проверка "сегодня", "вчера", "завтра"
Простейшие сравнения:
DateTime date = new DateTime(2025, 6, 18);
if (date.Date == DateTime.Today)
Console.WriteLine("Сегодня!");
else if (date.Date == DateTime.Today.AddDays(-1))
Console.WriteLine("Вчера!");
else if (date.Date == DateTime.Today.AddDays(1))
Console.WriteLine("Завтра!");
Вычисление возраста
Одна из самых частых задач — корректное вычисление возраста человека. Простое вычитание годов не всегда работает правильно:
public static int CalculateAge(DateTime birthDate, DateTime currentDate)
{
int age = currentDate.Year - birthDate.Year;
// Если день рождения ещё не наступил в этом году
if (currentDate.Month < birthDate.Month ||
(currentDate.Month == birthDate.Month && currentDate.Day < birthDate.Day))
{
age--;
}
return age;
}
// Использование
DateTime birth = new DateTime(1990, 8, 15);
DateTime today = DateTime.Today;
int age = CalculateAge(birth, today);
Console.WriteLine($"Возраст: {age} лет");
Работа с рабочими днями
Часто нужно вычислить количество рабочих дней между датами, исключая выходные:
public static int CountWorkingDays(DateTime startDate, DateTime endDate)
{
int workingDays = 0;
DateTime current = startDate;
while (current <= endDate)
{
if (current.DayOfWeek != DayOfWeek.Saturday &&
current.DayOfWeek != DayOfWeek.Sunday)
{
workingDays++;
}
current = current.AddDays(1);
}
return workingDays;
}
6. Как связаны основные классы
graph TD
A(DateTime) --вычитание--> B(TimeSpan)
A2(DateTime) --AddDays, AddMonths--> A
A --ToLocalTime/ToUniversalTime--> C(DateTimeOffset)
D(DateOnly) --ToDateTime--> A
E(TimeOnly) --ToTimeSpan--> B
A --DayOfWeek, Day, Month, Year--> F(Числовые свойства)
B(TimeSpan) --TotalDays, TotalHours, ...--> G(Свойства длительности)
7. Быстрый "справочник": что делать если...
| Задача | Что использовать | Пример |
|---|---|---|
| Узнать разницу между датами | |
|
| Добавить 2 недели к дате | |
|
| Вычислить возраст | Формула c и проверкой месяца/дня |
См. раздел выше |
| Получить/установить только дату | |
|
| Получить/установить только время | |
|
| Сравнить даты | Операторы , , , |
|
| Перевести в другой часовой пояс | |
|
| Узнать номер недели в году | |
см. документацию |
| Узнать день недели | |
|
| Посчитать рабочие дни | Цикл с проверкой |
См. раздел выше |
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ