16. 练习:万年历

更新於 發佈於 閱讀時間約 17 分鐘
raw-image

Hi, 大家好。我是茶桁。

上一节课最后,我让我家去预习一下日历和时间的相关模块,不知道大家有没有去预习。不管如何,这节课,让我们开始做一个练习:万年历。

没有预习的小伙伴也跟着一起,在本次练习完成的时候,相信你会对这些模块有了初步的了解。

好,让我们开始吧。

首先,我们需要来看看calendar.monthrange()这个函数,它属于calendar模块内,返回指定年份和月份的数据,月份的第一天是周几,和月份中的天数。

 import calendar
 ​
 res = calendar.monthrange(2023, 6)
 print(res)
 ​
 ---
 (3, 30)

我们接收了返回值,但是这个3和30分别是什么意思呢?我们打开日历看一下就明白了:

raw-image

如图所见,2023年的6月份一共是30天,第一天是周四。这也正是(3, 30)的含义。之所以是3而不是4,是因为是从0开始计算的,也就是说,周一是0。比如,2023年5月的第一天就是周一,我们来看看是不是这么回事:

 res = calendar.monthrange(2023, 5)
 print(res)
 ​
 ---
 (0, 31)

那有了这个,我们要做一个当月的日历就简单了,还记得我们之前做过一个星星的矩阵吗?是一样的概念,这是这次直接换成了数字而已, 来,让我们从最基本框架开始(还是以6月份数据来做):

 days = res[1]
 week = res[0] + 1
 ​
 d = 1
 while d <= days:
     # 循环周
     for i in range(1, 8):
         print('{:0>2d}'.format(d), end=" ")
         d+=1
     print()
 ​
 ---
 01 02 03 04 05 06 07
 08 09 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28
 29 30 31 32 33 34 35

这样,我们就将天数打印出来了。可是,明眼人一眼就看出了问题,这一月只有30天,怎么得到的35天的?让我们来修复一下这个问题:

 days = res[1]
 week = res[0] + 1
 ​
 print('一   二   三   四   五   六   日')
 d = 1
 while d <= days:
     # 循环周
     for i in range(1, 8):
         # 判断是否输出
         if d > days:
             print('', end='')
         else:
             print('{:0>2d}'.format(d), end="   ")
         d+=1
     print()
 ​
 ---
 一   二    三   四   五    六   日
 01   02   03   04   05   06   07  
 08   09   10   11   12   13   14  
 15   16   17   18   19   20   21  
 22   23   24   25   26   27   28  
 29   30  

我们在代码中加了一层判断,如果循环中的d大于days了,那我们就直接输出空格,否则才正确输出格式化的数字,那么这样就可以不输出31-35了。

完成了,顺便还打印了一行星期几。可是问题是,没有和实际情况对齐对吧?没事,我们继续来改动。

 days = res[1]
 week = res[0] + 1
 ​
 print('一   二   三   四   五   六   日')
 d = 1
 while d <= days:
     # 循环周
     for i in range(1, 8):
         # 判断是否输出
         if d > days or (d==1 and i<week):
             print('     ', end='')
         else:
             print('{:0>2d}'.format(d), end="   ")
             d+=1
     print()
 ​
 ---
 一   二    三   四   五    六   日
                01   02   03   04  
 05   06   07   08   09   10   11  
 12   13   14   15   16   17   18  
 19   20   21   22   23   24   25  
 26   27   28   29   30    

我们在之前判断d大于days的判断上再加上一层,不仅如此,当d==1并且i小于week的时候,也都是出制表符,那自然最开始和最末尾不该出现数字的地方都被制表符补齐了。

我们再来多做一次实验,将月份改成7月来看看和实际情况是否相符, 并且,这次我们多加一些内容,将其中的年份和月份也都打印出来:

 year = 2023
 month = 7
 res = calendar.monthrange(year, month)
 ​
 days = res[1]
 week = res[0] + 1
 ​
 print(f'========= {year} 年  {month} 月 =========')
 print('一   二   三   四   五   六   日')
 print('='*32)
 d = 1
 while d <= days:
     # 循环周
     for i in range(1, 8):
         # 判断是否输出
         if d > days or (d==1 and i<week):
             print('     ', end='')
         else:
             print('{:0>2d}'.format(d), end="   ")
             d+=1
     print()
 ​
 ---
 ========= 2023 年  7=========
 一   二    三   四   五    六   日
 ================================
                          01   02  
 03   04   05   06   07   08   09  
 10   11   12   13   14   15   16  
 17   18   19   20   21   22   23  
 24   25   26   27   28   29   30  
 31  

我们来看看实际情况是不是如此:

raw-image

没错,确实如此。7月份的第一天从周六开始,一个月有31天,周一为最后一天。那说明,我们上面写的内容真实有效。

那现在要干嘛呢?当然是封装成一个函数,以yearmonth为参数,这样,不管我想要查询任意月份,只要我输入对应参数就可以了:

 def showdate(year, month):
     res = calendar.monthrange(year, month)
 ​
     days = res[1] # 当前月份的天数
     week = res[0] + 1 # 当前月份第一天是周几
 ​
     print(f'========= {year} 年  {month} 月 =========')
     print('一   二   三   四   五   六   日')
     print('='*32)
     # 实现日历信息的输出
     d = 1
     while d <= days:
         # 循环周
         for i in range(1, 8):
             # 判断是否输出
             if d > days or (d==1 and i<week):
                 print('     ', end='')
             else:
                 print('{:0>2d}'.format(d), end="   ")
                 d+=1
         print()
 ​
 showdate(2023, 12)
 ​
 ---
 ========= 2023 年  12=========
 一   二    三   四   五    六   日
 ================================
                     01   02   03  
 04   05   06   07   08   09   10  
 11   12   13   14   15   16   17  
 18   19   20   21   22   23   24  
 25   26   27   28   29   30   31  

我们尝试调用了一下封装好的函数,输出2023年12月份日历,大家可以看看自己手机里的日历,绝对真实可靠。

好了,现在我们要完成万年历的制作了。

万年历,自然是有一个初始值,那这个初始值必须是当前时间最妥当。不然你们试试打开你们的日历,看是不是打开默认都是指向的「今天」。

那么首先,让我们获取一下当前系统的年月,这个就需要用到我们的time模块里的localtime()方法,其返回参数如下:

 time.struct_time(tm_year=2023, tm_mon=8, tm_mday=13, tm_hour=1, tm_min=50, tm_sec=38, tm_wday=6, tm_yday=225, tm_isdst=0)

那我们如何从中拿到我需要的内容?我们接着看:

 import time
 dd = time.localtime()
 year = dd.tm_year
 month = dd.tm_mon
 ​
 showdate(year, month)
 ​
 ---
 ========= 2023 年  8=========
 一   二    三   四   五    六   日
 ================================
      01   02   03   04   05   06  
 07   08   09   10   11   12   13  
 14   15   16   17   18   19   20  
 21   22   23   24   25   26   27  
 28   29   30   31  

很明显,我们用yearmonth两个变量从得到的localtime里获取了其中的年份和月份信息。然后重新调用showdate()封装函数,将其传入。也就打印出了我们当前月份的日历。

可是这都是静态的,我们总不能就只看我们当月的月份。所以,我们接着扩展这个程序。

 import time
 ...
 ​
 while True:
     # 默认输出当前年月的日历信息
     showdate(year, month)
     print(' < 上一月     下一月 > ')
     c = input('请输入您的选择 "<" or ">":')
     # 判断用户的输入内容
     if c == '<':
         month -= 1
     elif c == '>':
         month += 1
     else:
         print('您输入内容错误,请重新输入"<"或者">"来选择。')
 ​
 ---
 ========= 2023 年  8=========
 一   二    三   四   五    六   日
 ================================
      01   02   03   04   05   06  
 07   08   09   10   11   12   13  
 14   15   16   17   18   19   20  
 21   22   23   24   25   26   27  
 28   29   30   31                  
  < 上一月     下一月 >
 >
 ========= 2023 年  9=========
 一   二    三   四   五    六   日
 ================================
                     01   02   03  
 04   05   06   07   08   09   10  
 11   12   13   14   15   16   17  
 18   19   20   21   22   23   24  
 25   26   27   28   29   30        
  < 上一月     下一月 >

我们在程序运行中没有图形界面,无法接收鼠标信息,那就用输入<>来代替一下,其逻辑是相同的。

可以看到,我们做了一个判断,当输入<的时候,我月份数字减少,当我们输入>的时候,月份数字增加。所以当我们输入>的时候,表示下一月,数字增加,也就打印出了9月份的月份信息。

可是问题又来了,我们总不能无限加或者无限减下去吧,12月份之后不可能是13月份吧。这又该怎么办呢?

别着急,我们继续研究下该怎么改善:

 import time
 ...
 ​
 while True:
     ...
     # 判断用户的输入内容
     if c == '<':
         month -= 1
         if month < 1:
             month = 12
             year -= 1
     elif c == '>':
         month += 1
         if month > 12:
             month = 1
             year += 1
     elif c == 'exit':
         break
     else:
         print('您输入内容错误,请重新输入"<"或者">"来选择。')

既然月份是固定的数字,那就是最好办的,我们让变量控制在范围内不就好了。如果超过数字了,那就改变年份,将月份回滚为最小值或者最大值不就好了。两个简单的if解决了问题。

这就完了吗?并没有。在打印的过程当中,我发现一个问题,就是我们的月份信息不断的叠加,那导致打印区变的过长,最终都没打印完全。这并不是我们想要的,如图:

raw-image

所以,其实我都还没验证到底12月份之后是否正常变为2024年1月了。忍不了,这个问题也必须要解决。

那如何解决呢?我想起来,在Linux命令中有一个clear命令,其功能就是将当前窗口内容清理掉。那Python中又有很多和系统操作相同的功能,这次有没有呢?就算没有,我记得os.system()似乎可以调用系统命令的。

那,我们试试看:

 import os
 while True:
     os.system('clear')
     # 默认输出当前年月的日历信息
    ...

实际操作了一下,无法在Jupyter Notebook中实现,但是当你将代码存储成.py文件之后,在shell中执行是完全可以实现的。如下图:

raw-image

至此,我们本次的练习「万年历」就完成了。

大家可以下载我的源码来研究,第16课,包含一个.ipynb笔记本文件和一个.py完整文件。

有什么问题,评论区留言。

好了,下课,咱们下节课再见。

avatar-img
9會員
62內容數
从基础开始,再到Python,然后是CV、BI、NLP等相关技术。从头到尾详细的教授一边人工智能。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
茶桁的沙龍 的其他內容
Hi,大家好。我是茶桁。 系统内置模块就是安装完Python解释器之后,系统本身所提供的模块。我知道,咱们之前的课程里有学习系统的内置函数,这个模块和函数不是一个东西。模块这种东西,是需要导入后才可以使用的,比如:json, re, os等等。
Hi,大家好。我是茶桁。 上一节课,我们详细的介绍了文件读写的流程和原理,并用Python进行实际操作了一下。 那么这节课呢,我们利用之前所学的内容,尝试做一个小练习:建立一个登录注册系统。上节课我们在结尾的时候讲练习内容贴了出来,还记得要求吗?  实现功能:  1. 用户输入用户名和密码以及
在结束了Python数据类型学习之后,我们今天开始进入一个新的篇章。今天,让我们来详细了解一下在Python中如何去进行文件操作。
Hi, 大家好。我是茶桁 通过最近几节课的内容,我们已经了解到了大部分的容器类数据的特性和应用,今天这一节课是容器类数据的最后一部分。让我们今天来详细了解一下「集合」。
Hi,大家好。我是茶桁。 关于Python的数据类型,我们已经详细讲解了三种,字符串,列表和元组。那么今天,我们再来讲一种:字典。 字典也是一种数据的集合,由健值对组成的数据集合,字典中的键是不能重复的。 字典中的键必须是不可变的数据类型,常用的键主要是:字符串,整型... 实际上,在之前字
Hi,大家好。我是茶桁。 之前两节分别介绍了字符串和列表,今天,我们来讲讲另外一个常用到的数据类型:元组。 元组和列表很像,两者都是一组有序的数据的组合。但是也有很多不同点,比如元组内的元素一旦定义了就不可以再修改,因此元组称为不可变数据类型。 元组定义 元组的定义方式包括以下要点: 定义
Hi,大家好。我是茶桁。 系统内置模块就是安装完Python解释器之后,系统本身所提供的模块。我知道,咱们之前的课程里有学习系统的内置函数,这个模块和函数不是一个东西。模块这种东西,是需要导入后才可以使用的,比如:json, re, os等等。
Hi,大家好。我是茶桁。 上一节课,我们详细的介绍了文件读写的流程和原理,并用Python进行实际操作了一下。 那么这节课呢,我们利用之前所学的内容,尝试做一个小练习:建立一个登录注册系统。上节课我们在结尾的时候讲练习内容贴了出来,还记得要求吗?  实现功能:  1. 用户输入用户名和密码以及
在结束了Python数据类型学习之后,我们今天开始进入一个新的篇章。今天,让我们来详细了解一下在Python中如何去进行文件操作。
Hi, 大家好。我是茶桁 通过最近几节课的内容,我们已经了解到了大部分的容器类数据的特性和应用,今天这一节课是容器类数据的最后一部分。让我们今天来详细了解一下「集合」。
Hi,大家好。我是茶桁。 关于Python的数据类型,我们已经详细讲解了三种,字符串,列表和元组。那么今天,我们再来讲一种:字典。 字典也是一种数据的集合,由健值对组成的数据集合,字典中的键是不能重复的。 字典中的键必须是不可变的数据类型,常用的键主要是:字符串,整型... 实际上,在之前字
Hi,大家好。我是茶桁。 之前两节分别介绍了字符串和列表,今天,我们来讲讲另外一个常用到的数据类型:元组。 元组和列表很像,两者都是一组有序的数据的组合。但是也有很多不同点,比如元组内的元素一旦定义了就不可以再修改,因此元组称为不可变数据类型。 元组定义 元组的定义方式包括以下要点: 定义
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
2024 0611 今日塔羅:時空 Time Space   端午連假總共三天,第一天,忙著跟朋友相約聊天。 第二天,忙著趕功課進度,整理電腦資料,清潔家裡。 第三天,睽違很久的睡到自然醒,中午跟家人吃飯相聚。 快樂時光好快就結束了。 接下來規律的學習日子也不錯。   今天哥哥說,他
Thumbnail
在日常工作中,我們經常需要計算兩個日期之間的天數。無論是計算專案進行的天數、員工的工作天數,還是活動的剩餘天數,這些操作在EXCEL中都能輕鬆實現。 其實日期要計算天數超級簡單 日期天數=結束日期-開始日期+1 為什麼要+1呢? 可以讀一下這篇⬇️ 🔗EXCEL小知識 | 計算日期
Thumbnail
原本排滿計畫的一天,變成隨心所欲的一天。時間,變得彈性而自在,而且還化繁為簡了,雖然我沒照計畫過這一天,卻過了豐盛的一天。
Thumbnail
【春分】 今天3月20日是24節氣之一的「春分」。 春分,為春季九十天的中分點,古時亦稱「日中」、「日夜分」、「仲春之月」。 春分時,全球晝夜除極點附近之外幾乎等長。 春分之後,北半球各地開始晝長於夜,南半球各地夜長於晝。
Thumbnail
還有一天就是春分 不知道大家在那天會怎樣慶祝? 如果慶祝和她對我們生活中可以有什麼好幫助?
Thumbnail
一下子 2024就過了1/6~ 變成剩下3/4 而我們的春天一年之計 即將隨著月底的白羊月展開新的一年 不過就我觀察和自己的感覺 其實這兩個月來 變化似乎就已經夠大了 果然冥王水瓶是不容小覷的 希望可以讓我一夕暴富 ((ㄟ! 接下來我們看今天星相 月亮在
Thumbnail
今天是特殊的一天,國曆2024年2月29日,四年相遇一次的日子,馬雅將這一天稱之為:「Hunab Ku 0.0」那麼這一天是如何用圖騰表達的呢?「每四年,銀河星系之月的第22天到第23天之間,都會有一個 Hunab Ku 0.0的日子。
Thumbnail
雨水,是入春後的第二個節氣。 通常是國曆2月18或19或20日。 2024年則是在2月19日。 為什麼廿四節氣都是用國曆呢? 因為它是根據地球繞行太陽的軌道來劃分。 繞行一圈為 360°,以春分為 0°(太陽直射赤道), 清明為 15°,每隔 15° 為一個節氣,依序排列。 正因為廿四節
Thumbnail
我們揮別了2023年,正式踏入2024年啦! 🎆🎆🎆🎆 在13月亮曆的系統裡,每一個周期的開始,都有引領接下來日子往前的意象。所以欲知2024事,先從2024.1.1了解起吧!
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
2024 0611 今日塔羅:時空 Time Space   端午連假總共三天,第一天,忙著跟朋友相約聊天。 第二天,忙著趕功課進度,整理電腦資料,清潔家裡。 第三天,睽違很久的睡到自然醒,中午跟家人吃飯相聚。 快樂時光好快就結束了。 接下來規律的學習日子也不錯。   今天哥哥說,他
Thumbnail
在日常工作中,我們經常需要計算兩個日期之間的天數。無論是計算專案進行的天數、員工的工作天數,還是活動的剩餘天數,這些操作在EXCEL中都能輕鬆實現。 其實日期要計算天數超級簡單 日期天數=結束日期-開始日期+1 為什麼要+1呢? 可以讀一下這篇⬇️ 🔗EXCEL小知識 | 計算日期
Thumbnail
原本排滿計畫的一天,變成隨心所欲的一天。時間,變得彈性而自在,而且還化繁為簡了,雖然我沒照計畫過這一天,卻過了豐盛的一天。
Thumbnail
【春分】 今天3月20日是24節氣之一的「春分」。 春分,為春季九十天的中分點,古時亦稱「日中」、「日夜分」、「仲春之月」。 春分時,全球晝夜除極點附近之外幾乎等長。 春分之後,北半球各地開始晝長於夜,南半球各地夜長於晝。
Thumbnail
還有一天就是春分 不知道大家在那天會怎樣慶祝? 如果慶祝和她對我們生活中可以有什麼好幫助?
Thumbnail
一下子 2024就過了1/6~ 變成剩下3/4 而我們的春天一年之計 即將隨著月底的白羊月展開新的一年 不過就我觀察和自己的感覺 其實這兩個月來 變化似乎就已經夠大了 果然冥王水瓶是不容小覷的 希望可以讓我一夕暴富 ((ㄟ! 接下來我們看今天星相 月亮在
Thumbnail
今天是特殊的一天,國曆2024年2月29日,四年相遇一次的日子,馬雅將這一天稱之為:「Hunab Ku 0.0」那麼這一天是如何用圖騰表達的呢?「每四年,銀河星系之月的第22天到第23天之間,都會有一個 Hunab Ku 0.0的日子。
Thumbnail
雨水,是入春後的第二個節氣。 通常是國曆2月18或19或20日。 2024年則是在2月19日。 為什麼廿四節氣都是用國曆呢? 因為它是根據地球繞行太陽的軌道來劃分。 繞行一圈為 360°,以春分為 0°(太陽直射赤道), 清明為 15°,每隔 15° 為一個節氣,依序排列。 正因為廿四節
Thumbnail
我們揮別了2023年,正式踏入2024年啦! 🎆🎆🎆🎆 在13月亮曆的系統裡,每一個周期的開始,都有引領接下來日子往前的意象。所以欲知2024事,先從2024.1.1了解起吧!