Определение ближайшего дня рождения сотрудника

Задача: Сотрудники организации
Дан список сотрудников организации, в котором указаны их фамилии, имена и даты рождения. Напишите программу, которая определяет самого молодого сотрудника, празднующего свой день рождения в течение ближайших семи дней от текущей даты.

Формат входных данных На вход программе в первой строке подается текущая дата в формате DD.MM.YYYY, в следующей строке вводится натуральное число n — количество сотрудников, работающих в организации. В последующих n строках вводятся данные о каждом сотруднике: имя, фамилия и дата рождения, разделённые пробелом. Дата рождения указывается в формате DD.MM.YYYY.

Формат выходных данных Программа должна определить самого молодого сотрудника, празднующего свой день рождения в течение ближайших семи дней, и вывести его имя и фамилию, разделив пробелом. Если таких сотрудников нет, программа должна вывести текст:

Дни рождения не планируются Примечание 1. Гарантируется, что у всех сотрудников даты рождения различны.

Примечание 2. Например, для даты 01.11.2021 ближайшими семью днями являются:

02.11.2021, 03.11.2021, 04.11.2021, 05.11.2021, 06.11.2021, 07.11.2021, 08.11.2021
Написал два варианта 1 вариант

from datetime import datetime, timedelta

def find_youngest_birthday(employees, current_date):
    # Преобразуем текущую дату в объект datetime
    current_date = datetime.strptime(current_date, '%d.%m.%Y')
    
    # Инициализируем переменные для хранения самого молодого сотрудника и его даты рождения
    youngest_employee = None
    youngest_age = None
    youngest_birthday = None
    
    # Перебираем всех сотрудников
    for employee in employees:
        # Преобразуем дату рождения сотрудника в объект datetime
        birthday = datetime.strptime(employee['birthday'], '%d.%m.%Y')
        
        # Проверяем, празднует ли сотрудник свой день рождения в течение ближайших семи дней
        if (birthday.replace(year=current_date.year) - current_date).days >= 0 and (birthday.replace(year=current_date.year) - current_date).days <= 7:
            # Рассчитываем возраст сотрудника на момент текущей даты
            age = current_date.year - birthday.year
            if current_date.month < birthday.month or (current_date.month == birthday.month and current_date.day < birthday.day):
                age -= 1
            
            # Если это самый молодой сотрудник, то обновляем переменные
            if youngest_age is None or age < youngest_age:
                youngest_employee = employee
                youngest_age = age
                youngest_birthday = birthday
            elif age == youngest_age and birthday > youngest_birthday:
                youngest_employee = employee
                youngest_birthday = birthday
                
    # Если найден хотя бы один сотрудник, празднующий свой день рождения в течение ближайших семи дней, то возвращаем его имя и фамилию
    if youngest_employee:
        return f"{youngest_employee['name']} {youngest_employee['surname']}"
    else:
        # Иначе возвращаем текст "Дни рождения не планируются"
        return "Дни рождения не планируются"

# Читаем входные данные
current_date = input()
n = int(input())
employees = []
for _ in range(n):
    name, surname, birthday = input().split()
    employees.append({'name': name, 'surname': surname, 'birthday': birthday})

# Вызываем функцию и выводим результат
print(find_youngest_birthday(employees, current_date))

но при тесте 1

Test input:
14.11.2021
3
Иван Петров 16.11.1995
Петр Сергеев 14.11.1997
Сергей Романов 17.11.1994
Test output:
Петр Сергеев

вместо Иван Петров

2 вариант

from datetime import datetime, timedelta

# Функция для парсинга даты из строки
def parse_date(date_str):
    return datetime.strptime(date_str, '%d.%m.%Y')

# Чтение текущей даты
current_date_str = input().strip()
current_date = parse_date(current_date_str)

# Определение диапазона дней
start_date = current_date + timedelta(days=1)
end_date = current_date + timedelta(days=7)

# Чтение количества сотрудников
n = int(input().strip())

# Список для хранения ближайших дней рождений
birthdays = []

# Обработка данных сотрудников
for _ in range(n):
    employee_data = input().strip()
    name, surname, birth_date_str = employee_data.split()
    birth_date = parse_date(birth_date_str)
    
    # Получаем день и месяц рождения, устанавливаем год на текущий
    birth_day_month = birth_date.replace(year=current_date.year)
    
    # Проверяем, попадает ли день рождения в диапазон
    if start_date <= birth_day_month <= end_date:
        birthdays.append((birth_day_month, name, surname))

# Если есть дни рождения, определяем самого молодого
if birthdays:
    # Сортировка по дате рождения
    birthdays.sort(key=lambda x: x[0])  # Сортируем по дате
    # Вывод имен самого молодого в диапазоне
    print(birthdays[0][1], birthdays[0][2])  # Молодой — это первый после сортировки
else:
    print("Дни рождения не планируются")

при тесте 4

10.11.2021
5
Иван Петров 11.11.1995
Петр Сергеев 12.11.1992
Сергей Романов 13.11.1996
Роман Григорьев 14.11.1994
Григорий Иванов 15.11.1995

выводит Иван Петров вместо Сергея Романова


Ответы (2 шт):

Автор решения: MBo

Самый молодой - у которого дата рождения позже, а не раньше, поэтому во втором варианте нужно выбирать последнего после сортировки (или лямбду сортировки модифицировать, или reverse=True).

В первом, т.к. текущий день не учитывается, нужно строгое сравнение дня

if (birthday.replace(year=current_date.year) - current_date).days > 0
→ Ссылка
Автор решения: Sobolenko.Evgeniy

Вот ваш первый вариант, доработанный чтобы проходил тест.

from datetime import datetime
from dateutil.relativedelta import relativedelta


def find_youngest_birthday(employees, current_date):
    # Преобразуем текущую дату в объект datetime
    current_date = datetime.strptime(current_date, '%d.%m.%Y')

    # Инициализируем переменные для хранения самого молодого сотрудника и его даты рождения
    youngest_employee = None
    youngest_age = None
    youngest_birthday = None
    # Перебираем всех сотрудников
    for employee in employees:
        # Преобразуем дату рождения сотрудника в объект datetime
        birthday = datetime.strptime(employee['birthday'], '%d.%m.%Y')

        # Проверяем, празднует ли сотрудник свой день рождения в течение ближайших семи дней
        diff_date_in_days = (birthday.replace(year=current_date.year)-current_date).days
        if diff_date_in_days < 0:
                    diff_date_in_days = (birthday.replace(year=current_date.year+1)-current_date).days
        if 0 < diff_date_in_days <= 7:
            # Рассчитываем возраст сотрудника на момент текущей даты
            age = relativedelta(current_date, birthday).years

            # Если это самый молодой сотрудник, то обновляем переменные
            if youngest_age is None or age < youngest_age:
                youngest_employee = employee
                youngest_age = age
                youngest_birthday = birthday
            elif age == youngest_age and birthday > youngest_birthday:
                youngest_employee = employee
                youngest_birthday = birthday

    # Если найден хотя бы один сотрудник, празднующий свой день рождения в течение ближайших семи дней, то возвращаем его имя и фамилию
    if youngest_employee:
        return f"{youngest_employee['name']} {youngest_employee['surname']}"
    else:
        # Иначе возвращаем текст "Дни рождения не планируются"
        return "Дни рождения не планируются"


def test_find_youngest_birthday():
    test_case_employees = [{'name': 'Иван', 'surname': 'Петров', 'birthday': '11.11.1995'},
                           {'name': 'Петр', 'surname': 'Сергеев', 'birthday': '12.11.1992'},
                           {'name': 'Сергей', 'surname': 'Романов', 'birthday': '13.11.1996'},
                           {'name': 'Роман', 'surname': 'Григорьев', 'birthday': '14.11.1994'},
                           {'name': 'Григорий', 'surname': 'Иванов', 'birthday': '10.11.1995'}
                           ]
    result = find_youngest_birthday(test_case_employees, '10.11.2021')
    assert result == 'Сергей Романов'
    
test_find_youngest_birthday()
    

Но конечно, код можно сделать более простым и выразительным:

def find_youngest_birthday(employees, current_date):
    # Преобразуем текущую дату в объект datetime
    current_date = datetime.strptime(current_date, '%d.%m.%Y')
    
    def get_diff_in_days(_employee, _current_date):
        _birthday_as_date = datetime.strptime(_employee['birthday'], '%d.%m.%Y')
        _employee['birthday'] = _birthday_as_date
        result = (_birthday_as_date.replace(year=current_date.year)-_current_date).days
        if result < 0:
            result = (_birthday_as_date.replace(year=current_date.year+1)-_current_date).days
        return result
    # ищем сотрудников с датой рождения через 1-7 дней
    employees_in_condition = [e for e in employees if 0< get_diff_in_days(e, current_date) <= 7]
    # оставляем самого молодого
    youngest_employee_in_condition = next(iter(sorted(employees_in_condition, key=lambda e: e['birthday'],reverse=True)), None)

    return youngest_employee_in_condition or "Дни рождения не планируются"
→ Ссылка