Avatar ·

Как вычислить возраст человека на основе даты рождения в C#?

Всем привет! Я начинающий C# разработчик и столкнулся с, казалось бы, простой задачей — посчитать возраст пользователя на основе его даты рождения. У меня есть переменная `DateTime birthday` (например, `new DateTime(1990, 5, 15)`), и мне нужно получить целое число полных лет на сегодняшний день. Я попробовал самый очевидный способ — вычесть дату рождения из текущей даты и взять разницу в годах: ```csharp DateTime today = DateTime.Today; int age = today.Year - birthday.Year; ``` Но это не работает корректно! Если у человека день рождения ещё не наступил в этом году, то возраст получается завышенным на 1 год. Например, если сегодня 1 января 2025, а день рождения 15 мая 1990, то мой код выдаст 35 лет, хотя на самом деле человеку ещё 34. Я также пробовал использовать `TimeSpan`: ```csharp TimeSpan difference = today - birthday; int age = (int)(difference.TotalDays / 365.25); ``` Но это даёт неточные результаты из-за високосных годов и округления. Подскажите, как правильно и надёжно вычислить возраст? Нужно ли учитывать високосные годы? Как быть с часовыми поясами, если дата рождения хранится без времени? Буду благодарен за подробный пример с объяснением. <<>>

Правильный способ вычисления возраста в C#

Основная проблема вашего подхода — вы не учитываете, прошёл ли уже день рождения в текущем году. Вот классическое, надёжное решение, которое работает для любых дат, включая високосные годы:

public static int CalculateAge(DateTime birthDate, DateTime referenceDate)
{
    // Сначала вычисляем разницу в годах
    int age = referenceDate.Year - birthDate.Year;

    // Если день рождения ещё не наступил в этом году, вычитаем 1
    if (referenceDate.Month < birthDate.Month || 
       (referenceDate.Month == birthDate.Month && referenceDate.Day < birthDate.Day))
    {
        age--;
    }

    return age;
}

// Использование:
DateTime birthday = new DateTime(1990, 5, 15);
int age = CalculateAge(birthday, DateTime.Today);
Console.WriteLine($"Возраст: {age} лет");

Как это работает

  • Шаг 1: Вычисляем разницу в годах: referenceDate.Year - birthDate.Year
  • Шаг 2: Проверяем, прошёл ли день рождения в этом году. Если месяц рождения больше текущего месяца ИЛИ (месяц равен, но день рождения ещё не наступил) — вычитаем 1 год.

Этот метод не использует приблизительные значения (365.25 дней) и не зависит от високосных годов — он работает на уровне календарной логики.

Учёт часовых поясов и времени

Если ваша дата рождения содержит время, а вы сравниваете с DateTime.Now (а не DateTime.Today), нужно быть осторожным:

// Если birthDate включает время (например, 15.05.1990 14:30)
public static int CalculateAgeWithTime(DateTime birthDate, DateTime now)
{
    int age = now.Year - birthDate.Year;
    if (now < birthDate.AddYears(age)) // сравниваем с моментом дня рождения в этом году
    {
        age--;
    }
    return age;
}

Рекомендуется использовать DateTime.Today (или Date) для точного сравнения по дням, если время рождения неизвестно или неважно.

Расширенная версия с проверкой даты рождения

public static int CalculateAgeSafe(DateTime birthDate)
{
    if (birthDate > DateTime.Today)
        throw new ArgumentException("Дата рождения не может быть в будущем", nameof(birthDate));

    return CalculateAge(birthDate, DateTime.Today);
}

Почему не стоит использовать TimeSpan

  • 365.25 дней в году — это среднее значение, которое даёт погрешность при округлении.
  • Високосные годы не учитываются равномерно — в одни годы 365 дней, в другие 366.
  • Проблема с 29 февраля: если человек родился 29 февраля, то в невисокосные годы его "день рождения" формально — 28 февраля или 1 марта. Описанный выше метод корректно обработает это, так как 28 февраля < 29 февраля, и возраст будет уменьшен.

Альтернатива с использованием готовых библиотек

Если вы используете .NET 6+, можно воспользоваться DateOnly для упрощения:

public static int CalculateAge(DateOnly birthDate, DateOnly today)
{
    int age = today.Year - birthDate.Year;
    if (today.DayNumber < birthDate.AddYears(age).DayNumber)
        age--;
    return age;
}

Этот код компактнее и безопаснее, так как DateOnly явно работает только с датами без времени.

Итог: используйте метод с проверкой месяца и дня — он простой, точный и проверен годами. Удачи в разработке!

<<>>

Решение через статический метод .NET

Начиная с .NET 6, в классе DateTime появился удобный метод для вычисления возраста — DateTimeOffset.Compare(), но можно обойтись и более элегантным способом с использованием DateOnly и AddYears:

public static int CalculateAge(DateTime birthday)
{
    DateTime today = DateTime.Today;
    int age = today.Year - birthday.Year;
    
    // Если день рождения ещё не наступил в этом году
    if (birthday.Date > today.AddYears(-age))
    {
        age--;
    }
    
    return age;
}

Этот подход использует метод AddYears, который корректно обрабатывает високосные годы и 29 февраля. Если birthday больше, чем today.AddYears(-age) (т.е. день рождения в этом году ещё впереди), то возраст уменьшается на 1.

Обработка 29 февраля

Для людей, родившихся 29 февраля, метод AddYears автоматически "сдвигает" день рождения на 28 февраля в невисокосные годы. Это стандартное поведение .NET, которое многие считают правильным. Если вам нужно другое поведение (например, считать днём рождения 1 марта), придётся реализовать свою логику.

Преимущества

  • Компактный код — всего несколько строк.
  • Не нужно вручную сравнивать месяц и день.
  • Использует проверенную логику DateTime.AddYears.

Этот вариант чуть менее очевиден для новичков, но очень надёжен и рекомендуется для продакшн-кода.