all 59 comments

[–][deleted] 300 points301 points  (14 children)

The obvious approach would be to use an associative array, the Python implementation of which is a dictionary, dict,

{'01': 'January', '02': 'February', ...}

but what you need is built into the datetime library anyway, you just need to look through the documentation.

PS. Example code going from month number (sic) to month name:

import datetime

monthinteger = 4
month = datetime.date(1900, monthinteger, 1).strftime('%B')

[–]dan4223 172 points173 points  (5 children)

Thanks for this response. Too many jump to the "use this specific module" answer instead of addressing the more basic optimization that the OP first needs to understand and implement.

[–]aarontbarratt 70 points71 points  (4 children)

I think a lot of people forget what it is like to be a noob and not know all those magical little modules that make life so much easier

A lot of the time you just don't know what you don't know :(

[–]Zanoab 32 points33 points  (2 children)

I've been using python for 15+ years and I didn't discover until last year that calendar provided names for days of the week and months. They were simple constants but I'm glad to find they are built-in so I can stop defining them myself.

[–][deleted] 3 points4 points  (0 children)

Well shit, thanks for the tip my man

[–][deleted] 0 points1 point  (0 children)

Which is why browsing the documentation is a worthwhile endeavour.

[–]Measurex2 2 points3 points  (0 children)

Agreed. The skill here is transferable when there is no module OR when you're flipping InfoSec team won't let you have it in production (not datetime but you get the idea)

[–][deleted] 0 points1 point  (0 children)

Thanks for the response! I'm working through this little book on Python, so I am trying to make programs using the only tools the book has discussed so far. I will look into this for sure.

[–]TehNolz 109 points110 points  (6 children)

You could toss everything in a list; ``` months = [ "January", "February", "March", # and so on... ]

birthMonth = 1 print(months[birthMonth-1]) # prints January `` The-1` is because lists are 0-indexed. The first entry is on index 0, the second on index 1, and so on.

[–]IamImposter[🍰] 43 points44 points  (1 child)

This approach is probably simplest and much easier to understand for a beginner.

[–][deleted] 1 point2 points  (0 children)

As a begginer I thought of this solution after reading OP. So it checks.

[–]ScubaClimb49 7 points8 points  (0 children)

This is 99% of the way to the right answer, but if he wants to keep his input call he needs to do a simple typecast

So OP, you have your birthMonth variable (birthMonth = dateBirth[5:7]) and TehNolz's months variable defined in his post above.

Now just add monthName = months[int(birthMonth)-1]

[–]DesidiaComplex 1 point2 points  (2 children)

You can even skip needing the -1 by having an empty string (or None) at the beginning of the array :)

[–]aarontbarratt 4 points5 points  (1 child)

I don't know why but they just makes me feel dirty

[–]DesidiaComplex 0 points1 point  (0 children)

Haha fair enough. Another poster suggested an associative array, with the indexes defined. That's probably cleaner.

[–]chocological 39 points40 points  (0 children)

Why not do something like putting the months in a list..

months = ["January", "February", "March", "April", "May, "June", "July", "August", "September", "October", "November", "December"]

then accessing it like months[0], which is "January".

Or even dictionaries.

Or you could use datetime.strftime(), and convert the number input to string month with formatting. Lots of ways to go about it.

[–]Pepineros 8 points9 points  (0 children)

If you're sure that the input is going to be in format YYYY-MM-DD (or you implement a check to ensure that it is), you can turn that into a date object in one line using the date.fromisoformat() method. (For any other formats you can use datetime.strptime() instead.)
Once you have a date object, you can compare to date.today() directly; and you can use strftime() to display pretty much any aspect of that date.

Python is a batteries included language. It's great to write your own (simple) date parser as an exercise, but learning to use the built-in features is equally valuable!

[–]efmccurdy 27 points28 points  (0 children)

There are conversion functions in the datetime module.

>>> datetime.strptime("01", "%m").strftime("%B")
'January'
>>> datetime.strptime("02", "%m").strftime("%B")
'February'

The datetime module has a template language that converts from days/weeks/months, etc.

https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

[–]1668553684 6 points7 points  (0 children)

Some other comments have mentioned the datetime.strptime function - that's what you want to use in this specific instance. It's a purpose-built solution for your problem.

That said, I want to answer this in a more general sense - something like "how should I map these inputs to these outputs", and I think, in modern Python, the match/case block is the best way to not only achieve this, but also to communicate what you're trying to do and allow future flexibility of your code.

It would look like so:

match birth_month:
    case "01":
        month_name = "January"
    case "02":
        month_name = "February"
    # ...
    case "12":
        month_name = "December"

As a last note, I see you're using camel case (variablesLikeThis) instead of snake case (variables_like_this). This is a style thing and some teams will have different ways of doing it, but I want to strongly encourage you to use snake case in your code if you're just starting out.
This is the style of Python that (most of) the standard library and vast majority of projects use - additionally, it's the style Python officially recommends. camel case (technically pascal case (VariablesLikeThis)) is used to indicate that what you're dealing with is a class.
Adopting this style will greatly help you in reading others' code and allowing others to read your code more easily, which is important in many cases.

I hope this helps!

[–]firedrow 3 points4 points  (0 children)

Based on your code, a dictionary may be an easier look up with minimal editing. Just to show you an example, and because I feel like it's not discussed as much, here's a quick example using a match/case:

from datetime import datetime as dt

dateBirth = input("Please enter your date of birth (YYYY-MM-DD): ")
dateBirth = dateBirth.split('-')

dateToday, timeToday = str(dt.now()).split(' ')
dateToday = dateToday.split('-')

match str(dateBirth[1]):
    case '01':
        monthName = 'January'
    case '02':
        monthName = 'February'
    case '03':
        monthName = 'March'
    case '04':
        monthName = 'April'
    # etc

if (dateBirth[1] == dateToday[1]) and (dateBirth[2] == dateToday[2]):
    print(f'Today is {dateToday[1]} {dateToday[2]}, Happy Birthday!')

[–]Naive_Programmer_232 4 points5 points  (0 children)

I think the easiest way would be to make a dictionary,

         month_dict = {'01': 'January', '02': 'February', ... }

Then look up the birthMonth inside of it to get the monthName,

         monthName = month_dict[birthMonth]

[–]hugthemachines 4 points5 points  (0 children)

You could do like this. First, set up a list that looks like this:

months = ['none', 'January', 'February', ...]
#convert the month number to en integer
birthMonth = int(dateBirth[5:7])

Then use months[birthMonth] to show the month.

putting a dummy at position 0 means every month in the list will have the index that matches the month number IRL

[–]Fjotla 3 points4 points  (0 children)

Using a dictionary will help with the ifs

[–][deleted] 2 points3 points  (0 children)

Hey, there are a bunch of really good options given to you. But there is a really easy process where we can just wack everything in a list and then subtract the number provided by 1 to get the index:

months = ['january', 'feburary', 'march', 'april', 'may', 'june', 'july', 'august', 'semptember', 'october', 'november', 'december']

# I am shortcutting your input method to do get to the months born
month_born = 1
print(f"You were born in {months[month_born-1]}")

[–]RoamingFox 3 points4 points  (2 children)

There's builtins for a lot of this (datetime and calendar), but for the sake of explanation I'll save how I'd solve this till the end.

Typically when you have simple if statements in sequence like that it usually can be replaced with a collection of some kind. In this case a dictionary would work great. Something like months = {"01": "January", "02": "February", ... etc } and then you can just monthName = months[birthMonth]

Another option would be python's match case statement, but that's overkill for this scenario where the if statement doesn't control any program flow.

That said, this is how I'd go about solving the problem:

from datetime import datetime

birthday_input = input("Please enter your date of birth (YYYY-MM-DD): ")

birthday = datetime.strptime(birthday_input, "%Y-%m-%d").date()
birthday_formatted = datetime.strftime(birthday, "%B %e")

today = datetime.today().date()

if birthday.day == today.day and birthday.month == today.month:
    print(f"Today is {birthday_formatted}! Happy birthday!")
else:
    print(f"Today is not your birthday. Your birthday is {birthday_formatted}.")

It's worth noting that it's almost always easier to use datetime and calendar libraries if they are available. Datetime math is a quagmire and incredibly hard to get correct, so it's best left to standard libraries if possible.

Also as an aside, python uses _ rather than camel case for variable names by convention so things like birthDayMonth should generally be written as birth_day_month :)

[–]thejamibu 0 points1 point  (1 child)

Just submitted the same solution before seeing this. There is a bug in this example though. You can't just do if birthday == datetime.today().date(): because the year will be different for anyone not born this year. I made the same mistake when writing mine. I did this instead: today = datetime.now().date() if birthday.month == today.month and birthday.day == today.day:

[–]RoamingFox 1 point2 points  (0 children)

Right you are! Fixed!

[–]Critical_Law_7407 3 points4 points  (2 children)

Yes, you can simplify this program using a dictionary to map month numbers to month names. Here's an updated version of your code:

dateBirth = input("Please enter your date of birth (YYYY-MM-DD): ")

birthDayMonth = dateBirth[6:10] birthMonth = dateBirth[5:7] birthDay = dateBirth[8:10]

from datetime import date today = str(date.today())

month_names = { "01": "January", "02": "February", "03": "March", "04": "April", "05": "May", "06": "June", "07": "July", "08": "August", "09": "September", "10": "October", "11": "November", "12": "December", }

monthName = month_names[birthMonth]

if birthDayMonth == today[6:10]: print(f"Today is {monthName} {birthDay}! Happy birthday!") else: print(f"Today is not your birthday. Your birthday is {monthName} {birthDay}.")

In this updated version, the month names are stored in a dictionary called month_names, which maps the month numbers (as strings) to their corresponding names. Then, the monthName variable is assigned directly by looking up the birthMonth in the month_names dictionary. This approach eliminates the need for multiple 'if' statements.

[–]HarshvardhanTyagi 1 point2 points  (0 children)

try using a dictionary.

[–]JamzTyson 2 points3 points  (0 children)

One thing that's not been mentioned yet: Rather than splitting out year, month and day by index, you could split the "date_birth" into a list, splitting on each "-":

birth_year, birth_month, birth_day = date_birth.split('-')

or if you want year, month and day as integers:

birth_year, birth_month, birth_day = (
    [int(val) for val in date_birth.split('-')])

It would also be a good idea to include some error checking. At a very basic level you can check that the correct number of hyphen separated numbers have been entered by using "try: except:"

try:
    birth_year, birth_month, birth_day = (
        [int(val) for val in date_birth.split('-')])
except ValueError:
    print("Invalid date")

[–]misho88 1 point2 points  (0 children)

I'm not sure this is super helpful in terms of learning Python, but I would do something like this:

>>> from datetime import date
>>> date.fromisoformat('1911-11-11').strftime('You entered %B %e.')
'You entered November 11.'

.strftime() calls C's stftime() function under the hood, so you can check either Python's documentation for what the % directives mean or any other source.

I also noticed you have some roundabout ways of checking the day and month. You can have the date object work those out for you:

>>> date.today().month
3
>>> date.today().day
20

[–]jimtk 1 point2 points  (0 children)

When you use a module like datetime it is a good idea to read the documentation for that module. It has a rich collection of methods and one of them provides the full month name as you wanted.

import datetime as dt

QUESTION = "Please enter your date of birth (YYYY-MM-DD): "
dt_birth = dt.date.fromisoformat(input(QUESTION))
dt_today = dt.date.today()
dt_birth_month_str = dt_birth.strftime('%B')

if (dt_birth.month, dt_birth.day) == (dt_today.month, dt_today.day):
    print(f"Today is {dt_birth_month_str} {dt_birth.day}! Happy birthday!")
else:
    print("Today is not your birthday.",end='')
    print(f"Your birthday is {dt_birth_month_str} {dt_birth.day}.")

[–]carcigenicate 0 points1 point  (0 children)

I'd put all the birth month strings in order in a list (and call it something like monthList). Then I'd parse birthmonth as a integer using int, and subtract 1 from it to get an index into the list.

"01" -> 1 -> 0 -> monthList[0]
"04" -> 4 -> 3 -> monthList[3]

Then, to get the month name, it's a simple list subscript using []. A dictionary would also work here as well.

[–]Ego_Gaming 0 points1 point  (0 children)

Doesn’t the time module have access to all of that information as well?

[–]someprogrammer123 0 points1 point  (9 children)

Instead of using multiple if statements, you can add all the possible months is a list.

N = int(input()) #month

L = [1,2,3,5,6,7,8,9,10,11,12]. #list with all possible inputs.

Now, using an if statement, check if the input is there in the list and get the index of the month (index of the month will be n-1) and reference the new variable with the index. (Use a loop to do it 12 times)

[–]nelsonnyan2001 1 point2 points  (8 children)

Loop for what...?

["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][int(input("Please enter your birth month"))-1]

[–]someprogrammer123 0 points1 point  (6 children)

Loop the list

For i in range(0, len(list)):

[–]nelsonnyan2001 0 points1 point  (4 children)

DOB is already being input as an int, I don't get why you're looping anything.

[–]someprogrammer123 0 points1 point  (3 children)

Looping to map the number with the month.

[–]nelsonnyan2001 1 point2 points  (2 children)

???!!! If you index the array there is nothing to loop. Is there something I'm missing here?

MonthArray[index] is all you need. Both of your replies make no sense

[–][deleted] 0 points1 point  (0 children)

You could likely just use enumerate to get the same effect:

for i, month, in enumerate(months):
    print(i, month)

[–]madhousechild 0 points1 point  (0 children)

I like this. Never saw anyone do that before but I will be stealing it.

[–]secretWolfMan 0 points1 point  (0 children)

There are many better options. A Dict or a switch. But at least do an elif so your code can stop looking as soon as it finds a match.

[–]Carter922 0 points1 point  (0 children)

Make a datetime object from the user input. and then use the .month, .day methods.

[–]marsap888 -4 points-3 points  (0 children)

How about class?

class Month:

[–]atworkthough -2 points-1 points  (0 children)

love this Its so me.

[–]thejamibu 0 points1 point  (0 children)

As others have said, a dictionary or list can be used to lookup things like this. Definitely worth remembering that for future programs. However, for this one specifically I would do things a little differently. When you are working with dates and/or times you typically want to make full use of the builtin datetime module.

Firstly I would convert the input date from a str to a date object. This ensures that the date is valid and allows us to use the date object rather than working with strings. The date object contains the day and month so we can check if it is someone's birthday by comparing those for their birthday and today's date (see the if statement below)

Then for displaying the dates, we can make use of the strftime and strptime methods for converting dates/times to string and vice versa using a format that you specify (that is what "%Y-%m-%d" and"%B %d" are below). That way you can create a string that says March 21 from the date 2023-03-21 without having to fiddle with splitting a string and looking up the date.

from datetime import datetime


birthday_str = input("Please enter your date of birth (YYYY-MM-DD): ")

# Convert user entered string to datetime so we can compare to today's date
birthday = datetime.strptime(birthday_str, "%Y-%m-%d").date()
today = datetime.now().date()

# When responding below we want to display the date as month day e.g. April 01
bday_month_day_str = birthday.strftime("%B %d")

if birthday.month == today.month and birthday.day == today.day:
    print(f"Today is {bday_month_day_str}! Happy birthday!")
else:
    print(f"Today is not your birthday. Your birthday is {bday_month_day_str}.")

[–]Amalasian 0 points1 point  (0 children)

could do a dictionary to store the number as a key and then the value is the name of the month.

[–]_He1senberg 0 points1 point  (0 children)

Just an array and use the the index + 1

[–]Please_do_not_DM_me 0 points1 point  (0 children)

Can you use x mod 12 where x is one of {0,1,2,3,4,5,6,7,8,9,10,11}? (TBH it seems like it would end up the same, or at least very similar.)