首页 > Python笔记 阅读数:18

Python datetime模块完全攻略

顾名思义,datetime 模块是 Python 处理日期和时间的标准库,它就是 date 和 time 模块的结合。该模块提供了多种操作日期和时间的类,在支持日期、时间数学运算的同时,重点聚焦于如何能够更高效地支持日期的格式化输出。

datetime获取当前时间

我们先来看看如何获取当前日期和时间。
In [1]: from datetime import datetime  #导入日期类
In [2]: now = datetime.now()
In [3]: print(now)
2020-01-31 20:45:39.535529

对于 In [1] 处的代码,需要注意的是,datetime 是模块,datetime 模块中还包含一个同名的 datetime 类,我们通过 from datetime import datetime 导入的才是 datetime 这个类。

如果仅导入 datetime 类,则必须引用全名 datetime.datetime。如果这样的话,上述 In [2] 处的代码需要修改为如下形式。
now = datetime.datetime.now()

可以通过 type( ) 函数来验证 now 这个对象的身份,见 Out[4] 处,可以发现 datetime.now( ) 返回的是当前的日期和时间,其类型是 datetime。
In [4]: type(now)
Out[4]: datetime.datetime

如果要返回特定日期和时间的对象,可以直接用 datetime 的构造方法来生成这样的对象,方法如下。
In [5]: from datetime import datetime
In [6]: date = datetime(2020, 10, 31, 12, 59)
In [7]: print(date)
2020-10-31 12:59:00

我们还可以利用 datetime 类的属性 year、month、day、hour 和 minute 分别输出 datetime 对象的年、月、日、小时和分钟,示例如下。
In [8]: date.year
Out[8]: 2020
In [9]: date.month
Out[9]: 10
In [10]: date.day
Out[10]: 31
In [11]: date.hour
Out[11]: 12
In [12]: date.minute
Out[12]: 59

datetime转换为timestamp

在计算机中,时间实际上是用整型数字表示的。我们把 1970 年 1 月 1 日 00:00:00 UTC+00:00 时区的时刻称为 epoch time(纪元时间),记为 0。1970 年以前的时间为负数。

我们当前的时间就是相对于纪元时间流逝的秒数,称为 timestamp(时间戳)。有了这个时间戳,计算机可以很容易地比较时间的先后。这个时间是机器可读的,但对人而言,理解起来比较困难,因此通常需要转换。

通过如下代码可以方便地查看当前实际的时间戳。
In [1]: from datetime import datetime
In [2]: dt = datetime.now()
In [3]: dt.timestamp()
Out[3]: 1567999546.724838

孔夫子有句名言:“逝者如斯夫,不舍昼夜。”这句话形容时间像流水一样不停地流逝。因此当运行 In [3] 处的代码时,得到的运行结果(时间戳)永远会不一样,因为时间戳永远会单向递增。另外,还需要注意的是,Python 中的时间戳是一个浮点数。如果有小数位,小数位表示毫秒。

有时,用户输入的日期和时间是字符串,要处理这样的日期和时间,首先必须把字符串转换为 datetime。转换方法并不复杂,可通过 datetime.strptime( ) 实现,并需要制定一个日期和时间的格式化字符串,代码如下:
In [4]: from datetime import datetime
In [5] : cday = datetime.strptime('2020-10-30 11:00:30', '%Y-%m-%d %H:%M:%S')
In [6]: print(cday)
2020-10-30 11:00:30

strptime( ) 的第 1 个参数是日期字符串,很容易理解。这里,最复杂的部分莫过于该函数的第 2 个参数——变化多端的格式化参数。若格式标记出错,strptime( ) 就难以解析出正确的日期。常见的日期格式如表 1 所示。

表1:strptime( ) 函数中常见的日期格式
格式符 格式说明
%a 星期的英文单词缩写,如星期一返回 Mon
%A 星期的英文单词全称,如星期一返回 Monday
%b 月份的英文单词缩写,如一月返回Jan
%B 月份的英文单词全称,如一月返回January
%c 返回区域设置的适当日期和时间表示。不同的国家格式可能不同,如 2020/08/16 20:01:27 (中国)、Tue Aug 16 20:01:27 2020(美国)、Di 16 Aug 20:01:27 2020(德国)
%d
返回当前日期是当前月的第几天
%f 表示微秒(Microsecond ),范围 [0,999999]
%I
以12小时制表示当前小时数,范围 [1,12],如 01, 02,…,12
%J 返回当天是当年的第几天,范围 [001,366],如001, 002, …,366
%m 返回左侧 0 值填充的月份,范围 [0,12],如 01, 02,…,12
%M 返回左侧 0 值填充的分钟数,范围 [0,59],如 01, 02,.…,59
%P
返回上午(AM )或下午(PM )
%S
返回左侧 0 值填充的秒数,范围 [0,59].如 01, 02,.…,59
%U
返回当周是当年的第几周,以周日为第一天,如00, 01,.…,53
%W 返回当周是当年的第几周,以周一为第一天,如00, 01,.…,53
%w 返回当天是当周的第几天,范围 [0, 6], 6 表示星期天
%x 日期的字符串表示,如 07/10/2020,显小格式和区域设置有关
%X
时间的字符串表示,如 20:22:08
%y
用两个数字表示的年份,如 20
%Y
用四个数字表示的年份,如 2020
%z
表示与 UTC 时间的间隔,如果是本地时间,返回空字符串
%Z
表示时区名称.如果是本地时间.返回空字符串

datetime转换为字符串

如果已经有了 datetime 对象,我们要把它格式化为字符串显示给用户,转换是通过另外一个函数 strftime( ) 实现的。这里,同样需要格式化日期和时间字符串,因此,同样要用到表 1 中列举的格式。
In [1]: from datetime import datetime
In [2]: now = datetime.now()    #获取当前的时间和日期

In [3]: now.strftime("%Y")
Out [3]: '2020'
In [4]: now.strftime("%y")
Out [4]: '20'

datetime加减

有时候,我们需要计算某两个时间或日期的差值,比如说相隔多少个小时,相差多少天等。这时,可以对日期和时间进行加减。这种操作实际上就是向前或向后计算 datetime,得到一个新的 datetime。

Python 提供了很多“语法糖”,对 datetime 的加减,可以直接用加+和减-运算符操作。不过,这时需要引入一个特殊的类——时间差类 timedelta,示例代码如下。
In [1]: from datetime import datetime , timedelta
In [2]: now = datetime.now()
In [3]: print(now.strftime("%Y-%m-%d %H:%M"))
2019-09-09 20:58
In [4]: date = now + timedelta(hours = 2)
In [5]: print(date.strftime(H%Y-%m-%d %H:%M"))
2019-09-09 22:58
In [6]: date2 = now - timedelta(days = 2, hours = 12)
In [7]: print(date2.strftime("%Y-%m-%d %H:%M"))
2019-09-07 08:58

有了前面知识的铺垫,当我们想计算两个日期相隔多少时,利用时间差类 timedelta 就比较容易了,参见例 1。

【例 1】计算两个日期之间相隔的天数(gap-days.py)
from datetime import datetime, timedelta
 
list_1 = ["2020-10-07", '2013-09-01']
day1 = datetime.strptime(list_1[0], '%Y-%m-%d')  #将字符串转为datetime对象
day2 = datetime.stuptime(list_1[1], '%Y-%m-%d')  #同上

deltadays = day1 - day2           #时间差timedelta对象
print(deltadays.days)             #输出timedelta对象
程序执行结果为:

2593

有了时间差类 timedelta,我们可以直接输出时间差(如天数 days),而无须考虑闰年或闰月等复杂因素(第 08 行),因为该模块都提前为我们考虑好了。

相关文章