目录
1 基本思路
2 实现代码
3 运行效果
1 基本思路
首先确定要输出日历的表头,这里我用offset表示表头向右偏移量。当offset为0时,表头从星期一到星期日;当offset为1时,表头从星期日,星期一到星期六(向右平移一个单位)。代码里我使用的是offset为1即(星期日,星期一,星期二,星期三,星期四,星期五,星期六)这种表头。如果你想要其他表头可以修改offset。
表头确定了,你需要确定输入特定年、月对应的月的第一天应该为星期几,即需要确定开始输出日期时前面应该先输出多少单位的空格。这个开始星期几可以根据参照年月第一天对应星期几并结合该参照年月计算距离要输出年对应月份的天数确定,遍历年时如果年为闰年则加366天否则加365天,月份对应天数根据创建的月份天数数组确定,当年为闰年二月对应天数应该修改为29天。这里我选用的标准是(1800年1月1日,对应星期三),也就是说我们输出的年份不能小于1800年。天数计算完毕不要忘了对7取余,并且加上偏移量后再取余,因为可能有人将offset设置大于7。
单位空格我设置的是4个空格,表头以及下面的天数都是如此,这样我们可以得出标题以及下面分割线对应位宽为28。这里我还定义了一个函数用来根据你输入的位宽,填充字符,要输出的字符串来将字符串居中的函数,根据这个函数,只输入位宽与填充字符可以画出分割线。
得到要输出多少单位空格后就可以输出月份日历了,在输出的同时判断什么时候换行,并判断什么时候结束(根据月份天数数组确定)。
2 实现代码
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]
# 表头向右偏移量,当offset为0时从星期一开始,为1时从星期日开始
offset = 1
# 用来根据你想要输出位数,填充字符,以及显示的字符串来居中显示字符串
# 默认填充为空格,默认字符串为‘’,只填位数可以输出分隔线
def printCenter(len1, elem='', str1=' '):
fill = len1 - len(elem)
# fill1为字符串左边要填充的符号str1的个数
# fill2为右边字符个数
if fill % 2 == 0:
fill1 = fill // 2
fill2 = fill // 2
else:
fill1 = fill // 2
fill2 = fill // 2 - 1
print(str1 * fill1 + elem + str1 * fill2)
# 展示要显示的标题,包括年月以及星期的表头
def showTitle(year, month):
# 显示月份与年的标题
title = monthName[month - 1] + " " + str(year)
printCenter(28, title)
# 显示分割线
printCenter(28, str1='-')
# 显示星期的表头
dayNameI = 7 # 循环结束标志
day = (7 - offset) % 7 # 判断从哪个下标开始取星期名字字符串
while (dayNameI):
print(" " + dayName[day], end='')
day += 1
day %= 7
dayNameI -= 1
print() # 换行
# 判断是否为闰年
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
# 计算从1800年1月1日到要显示的指定年月的间隔天数(指定月前一月)
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 # 计算该月第一天对应星期数
# 判断什么时候换行
# 这个也控制初始填充的空格数(从第几个开始输出,共7个)
flag = (dayStart + offset) % 7
# 在输出日历前判断是否为闰年并修改月份天数数组monthNum
if ifLeapYear(year):
monthNum[1] = 29
else:
monthNum[1] = 28
# 输出开始前的空格
# 如果offset为0且月第一天为星期二,则前面需要输出一个单位的空格,单位为4(位宽)。
# 当该月第一天为星期为六(dayStart为6),offset为0时,flag为0(这只是flag为0的其中一种情况),输出空格时0-1为-1,将flag为0当成一种特殊情况
# 如果没有加if,当flag为0本来前面应该有6个单位空格,而-1*想要输出字符就什么也不输出
if flag == 0:
print(" " * 6, end='')
else:
print(" " * (flag - 1), end='')
#输出当月每一天
for day in range(monthNum[month - 1]):
print("%4d" % (day + 1), end='')
if flag % 7 == 0:
print()
flag += 1
print()
# 日历输出函数
def showCalendar(year, month):
showTitle(year, month)
showBody(year, month)
year = int(input("请输入年份:"))
month = int(input("请输入月份:"))
if year < 1800:
print("请输入大于等于1800年的年份")
else:
showCalendar(year, month)
3 运行效果
offset为1,输入年份为2023,月份为3月时
offset为1,输入年份为2023,月份为1月时
offset为0,输入年份为2023,月份为3月时(表头发生改变)