Table of contents
1 Basic idea
First of all, determine the header of the calendar to be output. Here I use offset to indicate the right offset of the header. When offset is 0, the table header is from Monday to Sunday; when offset is 1, the table header is from Sunday, Monday to Saturday (translate one unit to the right). In the code, I use an offset of 1 (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday). You can modify offset if you want other headers.
The table header is determined, you need to determine the day of the week that the first day of the month corresponding to the input specific year and month should be, that is, you need to determine how many units of spaces should be output before starting the output date. The starting day of the week can be determined according to the day of the week corresponding to the first day of the reference year and month and combined with the reference year and month to calculate the distance to output the number of days corresponding to the year. When traversing the year, if the year is a leap year, add 366 days, otherwise add 365 days, and the month corresponds The number of days is determined according to the created array of days in the month, and the number of days corresponding to February in a leap year should be changed to 29 days. The standard I choose here is (January 1, 1800, corresponding to Wednesday), that is to say, the year we output cannot be less than 1800. After calculating the number of days, don't forget to take the remainder of 7, and add the offset to take the remainder, because someone may set the offset to be greater than 7.
The unit space I set is 4 spaces, the same is true for the header and the number of days below, so that we can get that the corresponding bit width of the title and the dividing line below is 28. Here I also define a function to center the string according to the bit width you input, padding characters, and the output string. According to this function, you can draw a dividing line only by inputting the bit width and padding characters.
After getting how many units of spaces to output, you can output the monthly calendar. While outputting, judge when to change the line and when to end (determined according to the array of days in the month).
2 Implementation code
dayName = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] monthName = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] monthNum = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # The offset to the right of the table header, when offset is 0, it starts from Monday, and when it is 1, it starts from Sunday offset = 1 # Used to center the string according to the number of digits you want to output, padding characters, and the displayed string # The default filling is a space, the default string is '', only the number of digits can be filled to output the separator line def printCenter(len1, elem='', str1=' '): fill = len1 - len(elem) # fill1 is the number of symbols str1 to be filled on the left side of the string # fill2 is the number of characters on the right if fill % 2 == 0: fill1 = fill // 2 fill2 = fill // 2 else: fill1 = fill // 2 fill2 = fill // 2 - 1 print(str1 * fill1 + elem + str1 * fill2) # Display the title to be displayed, including the year, month and week headers def showTitle(year, month): # Display the title of the month and year title = monthName[month - 1] + " " + str(year) printCenter(28, title) # show dividing line printCenter(28, str1='-') # Show the header of the day of the week dayNameI = 7 # loop end flag day = (7 - offset) % 7 # Judging from which subscript to start taking the week name string while (dayNameI): print(" " + dayName[day], end='') day += 1 day %= 7 dayNameI -= 1 print() # new line # Determine whether it is a leap year def ifLeapYear(year): if year % 4 == 0 and year % 100 != 0 or year % 400 == 0: return True else: return False def showBody(year, month): totalDay = 0 # Calculates the number of days between January 1, 1800 and the specified year and month to be displayed (one month before the specified month) for i in range(1800, year): if ifLeapYear(i): totalDay += 366 else: totalDay += 365 for i in range(month - 1): totalDay += monthNum[i] dayStart = (totalDay + 3) % 7 # Calculate the week number corresponding to the first day of the month # Determine when to wrap # This also controls the number of blanks initially filled (output from the number, a total of 7) flag = (dayStart + offset) % 7 # Before outputting the calendar, judge whether it is a leap year and modify the array monthNum of the number of days in the month if ifLeapYear(year): monthNum = 29 else: monthNum = 28 # space before the beginning of the output # If offset is 0 and the first day of the month is Tuesday, a unit of space needs to be output in front, and the unit is 4 (bit width). # When the first day of the month falls on Saturday (dayStart is 6), and the offset is 0, the flag is 0 (this is only one of the cases where the flag is 0), and 0-1 is -1 when outputting spaces, and the flag is 0 as a special case # If there is no if, when the flag is 0, there should be 6 unit spaces in front of it, and -1* wants to output characters and nothing will be output if flag == 0: print(" " * 6, end='') else: print(" " * (flag - 1), end='') #Output for each day of the month for day in range(monthNum[month - 1]): print("%4d" % (day + 1), end='') if flag % 7 == 0: print() flag += 1 print() # Calendar output function def showCalendar(year, month): showTitle(year, month) showBody(year, month) year = int(input("Please enter the year:")) month = int(input("Please enter the month:")) if year < 1800: print("Please enter a year greater than or equal to 1800") else: showCalendar(year, month)
3 running effect
offset is 1, the input year is 2023, and the month is March
offset is 1, the input year is 2023, and the month is January
When the offset is 0, the input year is 2023, and the month is March (the header changes)