python中处理时间的模块有datetime、time、calendar三个模块。只有把这三个模块整合在一起,你才能随心所欲地使用python来处理时间。这篇文章就是为此而写的。文章的重点是梳理三个模块的设计脉络,让大家记住里面的API。需要的时候可以找到对应的方法。但由于日历模块的使用有限,本文不做介绍。一、概述datetime模块主要用来表示日期,也就是我们常说的年月日时分秒。日历模块主要用于表示年、月、日、星期几。时间模块主要关注时分秒,大致从功能的角度,我们可以认为三者是一种互补的关系,各自专注于一个领域。方便用户根据不同的使用目的选择方便的模块。2、从时间模块开始,为了学习时间模块,我们需要知道与时间相关的几个概念:1)、epoch假设我们要将时间表示为毫秒,例如1000000毫秒,那么有一个必须要解决的问题,这1,000,000毫秒的起点是什么,也就是我们的时间基准点是什么?比如我说你1.8米高,那么这个高度就是指你站立的地面。这个时间参考点是纪元。在Unix系统中,这个参考点是1970年1月1日0:00的时间点。2)、GMT、UTC我们上面说了epoch代表1970年的起点,那么这个1970年相对于哪个参考时间呢?一般来说,它是相对于格林威治标准时间,也称为GMT(格林威治标准时间)时间,也称为UTC(协调世界时)。为什么一次参考有两个名字?从历史上看,首先是GMT,然后是UTC。UTC是我们现在使用的时间标准,而GMT是旧的时间测量标准。UTC根据原子钟计算时间,而GMT根据地球自转和公转计算时间。因此,可以认为UTC是真正的参考时间,GMT与UTC的偏差为0。在实践中,我们的计算机中有一个硬件模块RCT,它会实时记录UTC时间。本模块采用独立电池供电,即使关机也不受影响。有了epoch的时间参考和UTC的参考,我们就可以准确的表示一个时间。3)、DST、tzone虽然我们可以准确的表达一个时间,但是在很多时候,我们还是需要根据地区的实际情况来调整时间。最常见的就是时区,tzone,相信大家都不陌生。这时候我们在说5:5的时间的时候,就需要加上5:5的时区来准确的指定一个时间。另一个时间调整是DST。DST的全称是DaylightSavingTime,意思是为了充分利用阳光,减少电力消耗,对时间进行人为调整,具体取决于不同国家和地区的政策法规。举个例子,假设你冬天7点起床,但夏天6点天亮,那么夏天来的时候人为加1小时,让你仍然认为自己7点起床时钟,但实际上它早了一个小时。那么,如果我们好奇的话,就要问了,python是怎么知道tzone和DST的值的呢?答案是通过环境变量。这里我们仅以linux为例进行说明。linux中有一个TZ环境变量,它的值类似这样:CST+08EDT,M4.1.0,M10.5.0,这个字符串可以这样解释,用空格分隔,分为三部分CST+08EDT,M4.1.0,M10.5.0中***部分的CST表示时区名称,即ChinaStandardTime,也就是我们所说的北京时间,+8表示北京时间加8小时为UTC时间。第二部分EDT表示夏令时的名称。我们说夏令时是不同的,因为各个国家和地区的政策法规不同。EDT后面也可以跟一个时间调整值,比如CST。但由于我国只在1986年到1992年的一段时间内实行过夏令时,现在已经废止了。所以后面就不用再调整时间了。第三部分表示执行夏令时的起止时间,我们不再详细解读。4)、时间表示、获取、转换time模块中获取时间的基本方法是t=time.time(),返回从epoch到现在的秒数(用浮点数表示),使用UTC时间。我们自然要将这个秒数转换成年月日时分秒的形式,转换有两种,一种是UTC时间,一种是我们时区调整后的时间.time模块为我们提供了两个方法,time.gmtime(t)time.localtime(t)都返回一个类struct_time的实例,它有如下属性:与以秒为单位的时间相比,这样的表示方式更适合我们了解。如果不带参数调用这两个函数,它们会在内部调用time.time(),并使用返回的秒数进行转换。相反,python也提供了将这两个struct_times转换成秒的方法。calendar.timegm()方法用于将UTC的struct_time(gmtime的返回对象)转换为距纪元时间的秒数。mktime()用于转换调整后的struct_time(即localtime的返回对象)时区到epoch的秒数意味着mktime方法会先在系统中找到时区和夏令时信息,并使用这些信息调整struct_time,然后再转换成秒。另一个常见的需求是在时间和表示时间的字符串之间进行转换。时间模块中的strftime和strptime就是这样做的。看名字就知道他们的意思了,strftime是stringformattime,用来把时间格式化成字符串strptime是stringparsetime,用来把字符串解析成时间。需要注意的是,这里的时间都是struct_time对象。如何格式化时间是很简单的知识,这里是官网文档的内容。除了这两个函数,time模块还提供了两个方便的方法来帮助将时间转换成字符串asctime用于将一个struct_time对象转换成一个标准的24个字符的字符串,如下所示:SunJun2023:21:051993ctime方法与asctime具有相同的效果,只是它接收秒数。在内部,秒数会先通过localtime转换成struct_time,然后和asctime一样。以上就是时间模块的核心内容。我尝试使用一个公式来帮助记住这些API时间点时间并将秒数传递给gm,将本地时间传递给struct_time。如果你想改回原来的秒数,你必须发回calendar.timegm和时间。mktimestringf用stringp格式化时间,就靠二哥了。你还觉得麻烦。asctime,ctime就是来帮你转换字符串的。前者接收struct_time,后者专门处理秒。分工合作并不费力。良好的时间模块基本功。做一个懂时间的人!下面,我们就开始学习datetime模块。3、datetime模块1)、概述time模块解决了时间的获取和表示,datetime模块进一步解决了快速获取和操作时间中的年月日时分秒信息的能力。简单的说,这个模块有3个核心类。日期类表示年、月、日,时间类表示时、分、秒、毫秒。不要将它与此处的时间模块混淆。一句顺口溜可以帮助记住这种情况:时间里没有时间,躲在datetime里不是坏事吗?嗯,我也这么认为。datetime类是日期和时间的组合。有一件事需要提前说明。时间类和日期时间类都有一个属性。它的值是一个tzinfo对象,包含time或datetime的时区信息。通常,此时间或日期时间对象是已知的,并且可以是准确的。转换为纪元以来的秒数。如果该属性设置为None,则此时的time对象或datetime对象没有时区信息。具体是代表本地时间还是utc时间需要我们自己在程序中确定。我们这里说的本地时间是指我们所在时区的时间,utc时间是指国际标准时间,也就是格林威治标准时间。下同。请记住,日期中没有时区信息。2)、从创建datetime开始创建datetime对象,我最常用的方法如下dt=datetime.datetime.fromtimestamp(time.time())上面,time.time()获取自epoch以来的秒数,fromtimestamp方法将秒数转换为日期时间对象。这里有个问题,这个datetime对象是UTC还是local?答案是本地的,这是此方法的默认行为。如果在fromtimestamp方法中传入一个表示时区的参数,即tzinfo对象,则会根据传入的时区信息进行转换。要获取表示当前本地时间的datetime对象,有两个方便的方法datetime.datetime.now()datetime.datetime.today()以上都是本地datetime对象。如何获取utc日期时间对象?有两个方法datetime.datetime.utcfromtimestamp()datetime.datetime.utcnow()我们也可以从一个字符串创建一个datetime对象,方法是datetime.striptime(date_string,format),也就是时间里的striptime方法先调用模块,获取struct_time对象,然后利用struct_time对象中的年月日时分秒信息构造datetime对象。同样,datetime类也提供了strftime()、asctime()、ctime()方法,相信不用说也知道是干什么的。datetime类还提供了一个combine方法,用于将一个日期对象和一个时间对象组合成一个datetime对象。需要注意的是,datetime模块中出现timestamp时,一般可以理解为time.time()返回的秒数3),date和time的创建和datetime对象的创建非常相似,datetime.date.today()datetime.date.fromtimestamp()可以创建一个日期对象。当然你也可以通过构造函数传入年月日来创建一个日期对象。相比之下,时间对象的创建非常有限,只能通过datetime.time([hour[,minute[,second[,microsecond[,tzinfo]]]]方法创建。4)、在实际使用上面三个对象操作和timedelta类的时候,我们有比较大的需求,需要比较和加减日期。得益于python的运算符重载能力,可以方便的在python中对date对象或datetime对象进行小于(<)比较和减(-)操作。注意这里只限于同类型的对象,不包括时间对象。两个日期对象相减,或者两个日期时间对象相减,差值用timedelta对象表示。同样,日期对象或日期时间对象也可以加上或减去时间增量对象。一个timedelta对象包含三个属性:days、seconds、microseconds,days属性可以取负值,其他两个属性只能取正值。您可以使用total_seconds()方法获取timedelta对象的秒表示。两个timedelta对象可以相加相减,但是不能做大小比较,因为没有意义。timedelta对象也可以乘以一个整数,或者通过//操作除以一个整数。也可以反过来,或者用abs函数获取4的绝对值,不总结,不进步datetime模块的设计结构,这样可以知道这些模块提供了哪些能力,想起来的时候你需要它。至于详细的API,应该很容易解决。
