前言

在程序开发中,对时间的记录和统计是最常用的功能之一,在Python中处理时间的模块则是timedatetime,今天就仔细介绍一下这两个模块的具体使用和转换方法。

 

time模块

time模块是Python中用于获取时间的最基础的模块,可以满足基本的时间获取、格式化输出等需求。

获取当前时间戳

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,因此无法表示1970年之前的日期,2038年以后的日期也不行。

timeStamp = time.time() # //1655623699.2784467

 

构造时间结构体

所谓时间结构体,就是time.struct_time类,可以根据时间单位传入时间的数值,得到一个用于表示时间的对象,简单的构造方式如下

timeTuple = (2020, 1, 2, 1, 51, 3, 2, 2, 0)
myTime = time.struct_time(timeTuple)

注意传入的参数需要是元组,元组内的9个元素依次分别为年、月、日、时、分、秒、一星期中的第几天、一年中的第几天、是否是夏令时,其中的夏令时使用几率很低,默认填写0就好。

另外其中的一星期中的第几天、一年中的第几天这两个参数要小心填写,因为不会进行校验。

得到时间结构体后就可以通过内置属性获取其中的某个时间单位。

print(myTime.tm_year, myTime.tm_mon, myTime.tm_mday, myTime.tm_hour, myTime.tm_min, myTime.tm_sec, myTime.tm_wday, myTime.tm_yday, myTime.tm_isdst, myTime.tm_mday)
# //2020 1 2 1 51 3 2 2 0

其中tm_mday代表了一个月中的第几天。

 

获取当前时区的时间

time.localtime()

获取当前时区的时间结构体。

可以将时间戳传入,转换成当前时区的时间结构体。

 

获取格林威治时间

time.gmtime() #1655623699.2784467

获取格林威治时区的时间结构体。

和localtime类似,同样可以将时间戳传入,得到时间戳对应的格林威治时区时间。

 

时间结构体转时间戳

time.mktime(myTime)

通过time库的mktime方法可以把时间结构体转换成时间戳。

 

时间戳的简单格式化

time.ctime(timeStamp) #//Mon Jun 20 22:22:01 2022

通过time库的ctime方法可以将时间戳简单格式化,参数为空时默认为当前时间。

 

时间结构体的简单格式化

time.asctime(myTime) #//Mon Jun 20 22:23:08 2022

通过time库的asctime方法可以将时间结构体简单格式化,参数为空时默认为当前时间。

 

时间结构体的自定义格式化

我最常用的格式化方式如下

time.strftime("%Y-%m-%d %H:%M:%S", myTime) #//2022-06-20 22:28:07

其中第一个参数为时间的展示格式,常用的参数和对应的含义如下,注意区分大小写:

  • %y 两位数的年份表示(00-99)
  • %Y 四位数的年份表示(0000-9999)
  • %m 月份(01-12)
  • %d 月内中的一天(0-31)
  • %H 24小时制小时数(00-23)
  • %I 12小时制小时数(01-12)
  • %M 分钟数(00-59)
  • %S 秒数(00-59)
  • %a 本地简化星期名称,例如Mon
  • %A 本地完整星期名称,例如Monday
  • %b 本地简化的月份名称,例如Jan
  • %B 本地完整的月份名称,例如January
  • %c 本地化的日期表示和时间表示
  • %j 年内的天序号(001-366)
  • %p 本地A.M.或P.M.的等价符,AM、PM
  • %U 一年中的星期数(00-53)星期天为星期的开始
  • %w 星期(0-6),星期天为星期的开始,序号0
  • %u 星期(1-7),星期一为星期的开始,序号1
  • %W 一年中的星期数(00-53)星期一为星期的开始
  • %c,简单格式化,例如Sun Jun 19 00:00:00 2022
  • %x 本地化的日期表示,例如06/19/2022
  • %X 本地化的时间表示,例如12:03:00
  • %z UTC偏移量,格式为 ±HHMM[SS[.ffffff]],例如东八区为+0800
  • %Z 当前时区的名称
  • %% %号本身

其中的数字都有左侧补0填充空值位。

 

格式化字符串转为时间结构体

相比起通过struct_time构造时间结构体,通过字符串生成时间结构体的方式更为常用

a = "Sat Mar 28 22:24:24 2016"
time.strptime(a,"%a %b %d %H:%M:%S %Y")

显然,strptime方法就是strftime的反向,时间格式参数也相同。

 

程序等待时间

这算是time库最常用的功能了吧,让程序等待一定的秒数,一般用于延时、等待通信结果等等。

time.sleep(5)

 

获取程序运行时长

time.process_time()

通过该方法可以很方便地获取Python程序运行时长。

 

datetime库

相比起time库,datetime库拥有着更加强大的功能,可以对时间对象进行更加复杂的处理,例如时间比较、时间相减等等,适用范围更广。

 

datetime.date类

date类代表一个理想化历法中的一天的日期,例如2000-03-23,其中的年必须为正整数,所以不支持公元前的表示。

date构建方式

myDate = datetime.date(2020, 2, 10)
print(myDate.year, myDate.month, myDate.day) #//2020 2 10

三个参数依次代表年、月、日,得到的日期对象可以通过year、month、day三个内置属性获取对应的时间单位。

两个date对象之间可以比较大小,并可以进行相减运算,得到一个时间段,也就是timedelta对象,后面会具体介绍,反过来一个date对象可以和时间段进行加减运算得到另一个date对象。

 

获取该日为星期几

print(myDate.weekday()) #//0
print(myDate.isoweekday()) #//1

其中weekday方法范围为[0, 6],isoweekday方法范围为[1, 7],根据需求使用即可。

 

获取今天的日期

today = datetime.date.today()

快速获取今天对应的date对象。

 

改变date对象的日期

newDate = myDate.replace(day = 23)

可以通过replace方法改变date对象的日期,得到一个新的date对象。

 

时间戳转date对象

newDate = datetime.date.fromtimestamp(time.time())

上面的写法等价于datetime.date.today()

 

date对象转time.struct_time

myTime = myDate.timetuple()

这样date对象就可以很方便地与time库进行转换,这一方法等价于以下形式

yday = myDate.toordinal() - datetime.date(myDate.year, 1, 1).toordinal() + 1   #本年的天序号
time.struct_time((myDate.year, myDate.month, myDate.day, 0, 0, 0, myDate.weekday(), yday, -1))

其中的toordinal()方法,意思是求该天的格里高利历天序号(从公元元年1月1日算第几天),反向方法datetime.date.fromordinal(x)则是根据天序号,求该天对应的date对象。

 

date对象转格里高利历对象

date对象是由年、月、日定义的,而格里高利历对象则是由年、一年中的第几个星期、一星期中的第几天组成,用星期取代月份的定义。

date对象可以很方便地转换成格里高利历对象

glglDate = myDate.isocalendar()

但由于每年的第一天不一定是星期一,所以定义一年中第一个包含星期四的星期为第一个星期。

date(2003, 12, 29).isocalendar()
#//datetime.IsoCalendarDate(year=2004, week=1, weekday=1)
date(2004, 1, 4).isocalendar()
#//datetime.IsoCalendarDate(year=2004, week=1, weekday=7)

由于这个原因,因此格里高利历纪年方式使用并不多,只做了解即可。

 

date对象简单格式化

print(myDate.isoformat()) #//2020-02-10

可以把date对象简单格式化为ISO 8601形式,即YYYY-MM-DD,一般使用足够了。

也可以通过str(myDate)方式格式化,实际调用的也是isoformat方法。

 

简单格式字符串转date对象

newData = datetime.date.fromisoformat("2022-11-01")

显然,fromisoformat方法就是isoformat方法的反向运算。

 

date对象自定义格式化

myDate.strftime("%b %d %Y") #//Feb 10 2020

格式参数和time.strftime方法的格式参数几乎一致,只多了个毫秒参数

  • %f 毫秒,例如000123

也可以通过myDate.__format__()方式调用,格式和参数一致。

如果要将格式化字符串转成date对象,可以使用datetime.datetime.strptime方法,使用方法和time.strptime方法一致。

 

datetime.time类

time类表示一天中的时间,该时间独立于任何特定日期。

 

time对象的构造方式

myTime = datetime.time(2, 20, 45, 1100)

4个参数依次代表时、分、秒、毫秒,也可以通过内置属性来获取对应的时间单位。

print(myTime.hour, myTime.minute, myTime.second, myTime.microsecond) #//2 20 45 1100

两个time对象可以比较大小,但不能进行相减运算。

通过datetime.time.mindatetime.time.max可以获取到时间的最小值(00:00:00)与最大值(23:59:59.999999)。

 

time对象替换时间

newTime = myTime.replace(hour=5)

与date对象类似,time对象也可以通过replace方法改变time对象的日期,得到一个新的time对象。

 

time对象的简单格式化

print(myTime.isoformat()) #//02:20:45.001100

与date对象类似,time对象也可以格式化为ISO 8601形式,即HH:MM:SS.mmmmmm。

也可以通过str(myTime)方式格式化,实际调用的也是isoformat方法。

 

简单格式字符串转time对象

datetime.time.fromisoformat("04:23:33")

与date对象类似,ISO 8601形式的字符串也可以转换为time对象。

 

time对象自定义格式化

myTime.strftime("%H %M %S") #//02 20 45

time对象的自定义格式化,也可以通过myTime.__format__()方式调用,格式参数和date对象完全一致,不再赘述。

 

datetime.datetime类

datetime对象是包含来自date对象和time对象的所有信息的单一对象,因此包括了date对象和time对象的内置属性和方法。

 

datetime对象的构造方式

myDatetime = datetime.datetime(2022, 6, 19, 15, 23, 32, 0)

参数依次为年、月、日、时、分、秒、毫秒,可以通过内置属性来获取对应的时间单位。

datetime对象可以比较大小,并可以进行相减运算,得到一个时间段(timedelta对象),反过来datetime对象可以和时间段进行加减运算得到一个新的datetime对象。

 

通过date对象和time对象组装datetime对象

myDatetime = datetime.datetime.combine(myDate, myTime)

 

datetime对象拆分成date对象和time对象

myDate = myDatetime.date()
myTime = myDatetime.time()

准确来说,这并不是拆分,而是新建了具有相同时间参数的对象。

 

获取当前时区的时间

datetime.datetime.today()
#或者datetime.datetime.now()

如果需要获取格林威治时间,可以使用datetime.datetime.utcnow方法。

 

时间戳转datetime对象

datetime.datetime.fromtimestamp(time.time())

和date对象的时间戳转换方法一致,如果需要转成格林威治时间,可以使用datetime.datetime.utcfromtimestamp方法。

 

datetime对象转时间戳

myTimeStamp = myDatetime.timestamp()

 

datetime对象转time.struct_time时间结构体

myTime = myDatetime.timetuple()

如果需要格林威治时间的话,可以使用myDatetime.utctimetuple方法。

借助这三个方法,就可以实现time库和datetime库之间的自由转换,方便对时间进行处理。

 

datetime对象替换时间

newDatetime = myDatetime.replace(year=2025)

与date对象和time对象的使用一致。

 

获取该日为星期几

print(myDatetime.weekday()) #//0
print(myDatetime.isoweekday()) #//1

其中weekday方法范围为[0, 6],isoweekday方法范围为[1, 7],与date对象的方法一致。

 

格里高利历相关方法

# 获取格里高利历日序号
print(myDatetime.toordinal()) #//738325
# 通过格里高利历日序号得到datetime对象
newDatetime = datetime.datetime.fromordinal(738325)
# datetime对象转格里高利历对象
calTime = myDatetime.isocalendar()

 

datetime对象的简单格式化

print(myDatetime.isoformat()) #//2022-06-19T02:20:45.001100

可以把date对象简单格式化为ISO 8601形式,很多数据库的时间数据都是这个格式存储的。

也可以通过str(myDatetime)方式格式化,实际调用的也是isoformat方法。

 

简单格式字符串转datetime对象

newDatetime = datetime.datetime.fromisoformat("2011-11-04T00:05:23")

以下几种形式都符合ISO 8601形式,可以正常识别。

  • 2011-11-04
  • 2011-11-04T00:05:23
  • 2011-11-04 00:05:23.283
  • 2011-11-04 00:05:23.283+00:00
  • 2011-11-04T00:05:23+04:00

 

datetime对象的自定义格式化

myDatetime.strftime("%Y-%m-%d %H:%M:%S")

与date对象和time对象的自定义格式化完全一致,也可以通过myDatetime.__format__()方式调用。

 

格式化字符串转datetime对象

datetime.datetime.strptime("2022-06-19 02:20:45", "%Y-%m-%d %H:%M:%S")

time.strptime方法一致。

 

datetime.timedelta类

timedelta类定义了一个时间范围,表示两个date或者datetime的时间间隔,用于实现时间的相减操作。

 

timedelta对象的构造方式

myTimedelta = datetime.timedelta(days=1.5, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

所有参数都是可选的并且默认为 0。

相比于date、time、datetime对象构造时严格要求参数为正整数并且需要在规定范围内,timedelta的这些参数则可以是整数或者浮点数,甚至可以是负数。

例如当输入days=1.5时,会自动转换成days=1,hours=12

因为这个特性,timedelta对象之间可以很方便地进行大小比较和加减乘(乘以数值)除运算,以及和date对象、datetime对象之间的加减法,并可以通过str(timedelta)获取格式化的字符串。

可以说timedelta对象是时间运算的核心。

 

计算timedelta对象的总时长

既然是时间段,当然可以计算时长,可以通过total_seconds()方法获取时间段内的秒数。

print(myTimedelta.total_seconds()) #//129600.0

 

总结

time库和datetime库算是Python中比较基础的模块了,今天把其中比较常用的功能整理了一下,也发现了很多新的使用技巧。

另外关于时区的处理,由于目前并未有相关的使用需求,就不细究了,以后有机会再补充。

 


真正的幸福不应该是绝对没有不良的情绪,
而是经得起困难和挫折的考验。

《幸福的方法》
——泰勒·本-沙哈尔