I recently made a birthday tracker app, that basically reads name
/birthdate
info from a CSV
file, puts all data in Person
objects, and orders them by date in a list, then re-orders the list, so it starts at the current date.
For example, right now the first few items in the list have birthdates in late November
and December
, and the rest follow still in order starting in January
going all the way to November 23rd
.
Thing is, at some point in my program I have to display current birthdays (simple, just pop the first element of the list if its birthdate is equal to current date), and also upcoming birthdays. Here's the code for it:
today_plus_3weeks = today d.timedelta(days=21)
# Take people who were born today and put them in a separate list
while people[0].birthdate.month == today.month and people[0].birthdate.day == today.day:
birthdays_today.append(people.pop(0))
# Take people who were born on dates between tomorrow and x later (default 3 weeks)
# and put them in a separate list
while initPeople.is_first_date_later(today_plus_3weeks, people[0].birthdate):
upcoming_birthdays.append(people.pop(0))
Up until recently, the upcoming birthdays thing was working fine, but I ran into a problem today. My program checks the first few upcoming dates, and they're all within three weeks. However, the next date is in January—
so, in theory, it should be rejected by the program and the loop should end... but it doesn't.
The problem is obvious when you look at the code I use to compare dates:
def is_first_date_later(date1, date2):
"""Returns True if the first date is later in the year than the second, False if not"""
return date1.month > date2.month or (date1.month == date2.month and date1.day > date2.day)
The condition is always True
because the date it's using for comparisons is in mid-December
, so the month
is always greater, or when it's equal the day
is greater. So I empty my whole list and end up with IndexError: list index out of range
. I can't really use the years to compare, because the dates are several years apart and years are not relevant to use in this context. I have access to them though, if I need them for anything at some point.
I'm really not sure what the best solution would be without massively complexing the code.
If it's needed, the full code is available here.
CodePudding user response:
I would start by writing a function to find the year and date of someone's next birthday. There are two cases:
- Their birthday is this year.
- Their birthday is next year.
def next_birthday(birthday_month, birthday_dayofmonth):
today = datetime.date.today()
bday_this_year = datetime.date(year=today.year, month=birthday_month, day=birthday_dayofmonth)
bday_next_year = datetime.date(year=today.year 1, month=birthday_month, day=birthday_dayofmonth)
if bday_this_year >= today:
return bday_this_year
elif bday_next_year >= today:
return bday_next_year
else:
raise Exception("This is impossible")
You can then use that function to find the number of days until the next birthday. The datetime library lets you subtract dates and find the number of days between them.
def days_until_next_birthday(birthday_month, birthday_dayofmonth):
"""Days until next birthday. If it is their birthday, return 0."""
today = datetime.date.today()
next_bday = next_birthday(birthday_month, birthday_dayofmonth)
return (next_bday - today).days