JavaRush /Курсы /C# SELF /Вычисления и вспомогательные классы для дат и времени

Вычисления и вспомогательные классы для дат и времени

C# SELF
15 уровень , 4 лекция
Открыта

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?

Свойство Описание
Days
Целое число дней
Hours
Часовая часть
Minutes
Минутная часть
Seconds
Секундная часть
TotalDays
Время в днях (дробное)
TotalHours
Время в часах (дробное)
TotalMinutes
Время в минутах (дробное)
TotalSeconds
Время в секундах (дробное)
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()}");
Метод Что добавляет (или вычитает при отрицательном числе)
AddDays(double)
Дни (поддержка дробей, например 1,5 дня)
AddMonths(int)
Месяцы (автоматически учитывает длину месяца)
AddYears(int)
Годы (даже с учётом високосных)
AddHours(double)
Часы
AddMinutes(double)
Минуты
AddSeconds(double)
Секунды
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. Быстрый "справочник": что делать если...

Задача Что использовать Пример
Узнать разницу между датами
TimeSpan duration = d2 - d1
(d2 - d1).Days
Добавить 2 недели к дате
date.AddDays(14)
date.AddDays(14)
Вычислить возраст Формула c
.Year
и проверкой месяца/дня
См. раздел выше
Получить/установить только дату
DateOnly
DateOnly.FromDateTime(DateTime.Now)
Получить/установить только время
TimeOnly
TimeOnly.FromDateTime(DateTime.Now)
Сравнить даты Операторы
<
,
>
,
==
,
.CompareTo()
if (d1 < d2) ...
Перевести в другой часовой пояс
DateTimeOffset + ToOffset
dto.ToOffset(TimeSpan.FromHours(3))
Узнать номер недели в году
Calendar.GetWeekOfYear()
см. документацию
Узнать день недели
date.DayOfWeek
Посчитать рабочие дни Цикл с проверкой
DayOfWeek
См. раздел выше
2
Задача
C# SELF, 15 уровень, 4 лекция
Недоступна
Разница между датами
Разница между датами
2
Задача
C# SELF, 15 уровень, 4 лекция
Недоступна
День недели
День недели
1
Опрос
Работа с датами, 15 уровень, 4 лекция
Недоступен
Работа с датами
Работа с датами, временем и таймзонами
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ