Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialRoderick Hung
Front End Web Development Techdegree Graduate 23,182 PointsHow to sort birthdays in chronological order in challenge 3?
How can I print upcoming birthdays in chronological order.
for person in people_list:
birthday_dt = date_str_to_obj(person)
now = datetime.datetime.now()
birthday_this_year = birthday_dt.replace(year=now.year)
birthday_next_year = birthday_dt.replace(year=now.year+1)
difference = birthday_this_year - now
turning_age = relativedelta.relativedelta(now, birthday_dt).years +1
if 0 < ((birthday_this_year-now).days) <= days or 0 < ((birthday_next_year-now).days) <= days:
print(F"{person['name']} turns {turning_age} in {difference.days} days on {birthday_dt.strftime('%B %d')}")
output
======== UPCOMING BIRTHDAYS ========
Marcelle turns 20 in 59 days on March 10
Arby turns 34 in 85 days on April 05
Fred turns 34 in 31 days on February 11
Jane turns 40 in 19 days on January 30
====================================
How can I make the output print:
======== UPCOMING BIRTHDAYS ========
Jane turns 40 in 19 days on January 30
Fred turns 34 in 31 days on February 11
Marcelle turns 20 in 59 days on March 10
Arby turns 34 in 85 days on April 05
====================================
3 Answers
Roderick Hung
Front End Web Development Techdegree Graduate 23,182 PointsI found that the code above has a bug if I changed the "now" variable to datetime.datetime(year=2023, month=11, day=1). The below code is refactored and with documentation.
def upcoming_birthdays(people_list, days):
# TODO: write code that finds all upcoming birthdays in the next 90 days and in chronological order
# 90 is passed in as a parameter from menus.py
# Template:
# PERSON turns AGE in X days on MONTH DAY
# PERSON turns AGE in X days on MONTH DAY
birthday_list = []
#paramaters are passed into the sort_birthday_list() that first creates an object for each person and appends
#to birthday_list. Using sort() on birthday_list to chronologically order each person object by their birthday.
def sort_birthday_list(person, turning_age, difference, birthday):
birthday_list.append({
'name': person['name'],
'turning_age': turning_age,
'difference': difference,
'birthday': birthday
})
birthday_list.sort(key=lambda item:item['birthday'])
#Looping through the people_list that was passed into upcoming_birthday() function and converting
#each string in person to a datetime object.
#converting each datetime object to the current year in "birthday_this_year" and also to next year in
#"birthday_next_year". The if elif statement below checks if the difference between "birthday_this_year"
#and "birthday_next_year is within 90 days or not". If the birth date is within 90 days, each person's parameters
#are passed into the sort_birthday_list().
for person in people_list:
birthday_dt = date_str_to_obj(person)
now = datetime.datetime.now()
birthday_this_year = birthday_dt.replace(year=now.year)
birthday_next_year = birthday_dt.replace(year=now.year+1)
difference_this_year = birthday_this_year - now
difference_next_year = birthday_next_year - now
turning_age = relativedelta.relativedelta(now, birthday_dt).years +1
if 0 < ((difference_this_year).days) <= days:
sort_birthday_list(person, turning_age, difference_this_year.days, birthday_this_year)
elif 0 < ((difference_next_year).days) <= days:
sort_birthday_list(person, turning_age, difference_next_year.days, birthday_next_year)
#loops through each person in birthday_list that has been chronologially ordered by birthday and within 90 days
#to print out person's name, the age they are turning, how many days until their birthday, and the month and day of birthday.
for person in birthday_list:
print(f"{person['name']} turns {person['turning_age']} in {person['difference']} days on {person['birthday'].strftime("%B %d")}")
#output
# ======== UPCOMING BIRTHDAYS ========
# Nova turns 24 in 27 days on November 28
# Declan turns 30 in 59 days on December 30
# Jane turns 40 in 90 days on January 30
# ====================================
Steven Parker
231,269 PointsAfter converting the strings to datetime objects, you can perform normal mathematical comparisons on the datetimes.
Earlier dates will be considered to be "less than" later dates, making it easy to sort them.
Roderick Hung
Front End Web Development Techdegree Graduate 23,182 PointsSteven Parker , I have converted the strings to datetime objects with the variable "birthday_dt" but not sure how I use math to compare each date.
Steven Parker
231,269 PointsOrdinary comparison operators can be used on the datetime variables, such as:
if birthday1_dt < birthday2_dt: # this will be true if birthday1 comes first
You can create a custom comparison function to use with sort() or sorted() to put the list in the desired order. Check the official online documentation for more details.
Roderick Hung
Front End Web Development Techdegree Graduate 23,182 PointsThanks Steven Parker . I used the sort method. Below is the code that will print all upcoming birthdays within 90 days in chronological order. Let me know if you think the code can be refactored further. Thanks.
def upcoming_birthdays(people_list, days):
# TODO: write code that finds all upcoming birthdays in the next 90 days
# 90 is passed in as a parameter from menus.py
# Template:
# PERSON turns AGE in X days on MONTH DAY
# PERSON turns AGE in X days on MONTH DAY
birthday_list = []
def sort_birthday_list(person, turning_age, difference, birthday_str_num, birthday_str_month_day):
birthday_list.append({
'name': person['name'],
'turning_age': turning_age,
'difference': difference,
'birthday_str': birthday_str_num,
'birthday_str_month_day': birthday_str_month_day
})
birthday_list.sort(key=lambda item:item['birthday_str'])
for person in people_list:
birthday_dt = date_str_to_obj(person)
now = datetime.datetime.now()
birthday_this_year = birthday_dt.replace(year=now.year)
birthday_next_year = birthday_dt.replace(year=now.year+1)
difference = birthday_this_year - now
turning_age = relativedelta.relativedelta(now, birthday_dt).years +1
if 0 < ((birthday_this_year-now).days) <= days or 0 < ((birthday_next_year-now).days) <= days:
sort_birthday_list(person, turning_age, difference.days, birthday_dt.strftime("%m %d"), birthday_dt.strftime('%B %d'))
for person in birthday_list:
print(f"{person['name']} turns {person['turning_age']} in {person['difference']} days on {person['birthday_str_month_day']}")
output
======== UPCOMING BIRTHDAYS ========
Jane turns 40 in 16 days on January 30
Fred turns 34 in 28 days on February 11
Marcelle turns 20 in 56 days on March 10
Arby turns 34 in 82 days on April 05
====================================
Steven Parker
231,269 PointsSteven Parker
231,269 PointsRoderick Hung — Normally, "best answer" would be the the one that contained the info that helped resolve your issue!
(you can still change that now)
In any case, glad I could help. And happy coding!