Python 有很多种方式处理日期和时间,常见的时间处理的模块是datetime、time、calendar。能融汇贯通的了解和使用这三个模块,才能轻而易举地用python处理时间。本文以此为目的,通过讲述各个时间模块的概述、函数及相关知识细节、以及相应的示例来讲透它们的使用方式。
这三个模块中,datetime(日期时间)模块主要是用来表示日期的,就是我们常说的年月日时分秒,calendar(日历)模块主要是用来表示年月日,是星期几之类的信息,time(时间)模块主要侧重点在时分秒,粗略从功能来看,我们可以认为三者是一个互补的关系,各自专注一块。方便用户依据不同的使用目的选用趁手的模块。
文章着重点在于梳理出三个模块的设计脉络,便于大家记忆里面的api。在需要的时候能够去查找相应的方法。由于文章篇幅较长,故将三个模块和示例的讲解拆分成几篇前后关联的文章,本文中重点讲解datetime模块。
一、概述
time模块是比较基础的一个模块,可满足对时间类型数据的基本处理;而 datetime模块可以看做是对time模块的一个高级封装,功能更加强大。time模块解决了时间的获取和表示,datetime模块则进一步解决了快速获取并操作时间中的年月日时分秒信息的能力。
datetime模块是这三个时间模块中使用的相对较为频繁,datetime有六个类,比较常用的有datetime、date、time、timedelta这四个,类date和类time可以看作是类datetime的子类别,虽然是分开的,但实际上这三个类的使用方法(函数)基本上是一样的,所以学精通类datetime的属性和方法,基本上可以无障碍的使用另两个类了。
需要特别注意的是,datetime模块中的类time和time模块间的区别,不要混淆它们的用法,它们其中一个只是datetime模块中的一个类别,需要用from datetime import time来进行引用,而另一个是一个独立的模块,只需要用import time。如果同时使用这两个'time',那请直接导入datetime模块和time模块,更细致的导入datetime模块中的类time会混淆两者的使用。
timedelta是datetime模块中的一个非常有用的模块,时间类型数据的计算可以通过timedelta方便快捷的实行,可以通过timedelta设置一个时间间隔,然后与指定时间进行计算,既可以获取某个时间范围内的目标,也可以计算时间间隔前后的日期时间。
有一点需要提前说明一下,time类和datetime类都有一个属性,它的值是一个tzinfo对象,里面包含了该time或者datetime的时区信息,一般称这个time或者datetime对象是aware的,它能够准确换算成自epoch开始的秒数。
如果该属性设置为None,那么,这时的time对象或者datetime对象就没有时区信息,具体它表示的是local time还是utc time,需要我们自己在程序中去决定。
这里我们所说的local time是指我们所在时区的时间, utc time指的就是国际标准时间,也就是格林尼治时间。在本文中不会涉及讲解市区和夏令时的相关操作,一切默认为localtime。
类datetime、date、time
datetime对象就是date对象和time对象的组合。
# 导入datetime模块三个核心的类
from datetime import datetime # class one:datetime 日期时间
from datetime import date # class two:date 日期
from datetime import time # class three:time 时间
创建
直接将时间的值逐个以参数的形式来创建
datetime(year,month,day,hour,minute,second,mircosecond)date(year,month,day)time(hour,minute,second,mircosecond)## 直接创建
datetime(2020,1,1,19,30,0,520)
date(2020,1,1)
time(19,30,0,520)
执行结果:
datetime.datetime(2020, 1, 1, 19, 30, 0, 520)
datetime.date(2020, 1, 1)
datetime.time(19, 30, 0, 520)
获取当前时间
获取当前日期用today,因为日期的最小计算单位是天,当前日期就是今天;date对象只有today一种获取当前时间的方法,datetime对象却有today和now两种,结果是一致的,time对象没有获取当前时间的方法,不过可以通过datetime对象来获取。
datetime.now() # 获取当前日期时间
datetime.today() # 获取当前日期时间
date.today() # 获取当前日期
执行结果:
datetime.datetime(2019, 12, 31, 14, 26, 21, 655429)
datetime.datetime(2019, 12, 31, 14, 26, 21, 658430)
datetime.date(2019, 12, 31)
三者间的关系
类date和类time可以从类datetime中分离出来,也可以通过combine方法合并成新的类datetime变量。
datetime.combine(datetime.date,datetime.time)dt = datetime.now() # 获取当前日期时间
dt
dt.date() # 提取日期部分
dt.time() # 提取时间部分
datetime.combine(dt.date(),dt.time()) # 合并日期和时间
执行结果:
datetime.datetime(2019, 12, 31, 14, 28, 36, 804160)
datetime.date(2019, 12, 31)
datetime.time(14, 28, 36, 804160)
datetime.datetime(2019, 12, 31, 14, 28, 36, 804160)
其他创建方式
除了直接以参数形式创建时间和获取当前时间这两种方式之外,还有三种通过其他形式的时间格式转换的方法可以创建时间:
fromtimestamp(timestamp) 以时间戳为参数fromordinal(ordinal) 以ISO日历公历序数为参数fromisoformat(date_string) 以字符串格式时间为参数其中时间戳最小单位为秒,包含了日期和时间的信息;ISO日历公历序数最小单位为天,仅包含了日期的信息。这两种方法只适用于datetime对象和date对象,time对象无法使用。
fromisoformat方法三种类都可以使用,但是它有着固定的输入格式要求,如果是非标准格式的字符串,那么无法使用该方法,后面的strptime方法才可以装换非标准格式的时间。
## datetime
datetime.fromtimestamp(1577777777.32452) # 时间戳转时间(以秒为单位)
datetime.fromordinal(737425) # 多格勒公历序树转日期(以天为单位)
datetime.fromisoformat("2020-01-01 12:00:00") # YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]]
## date
date.fromtimestamp(1577784872) # 时间戳转时间(以秒为单位)
date.fromordinal(739032) # 多格勒公历序树转日期(以天为单位)
date.fromisoformat("2020-01-01") # 字符转时间,仅支持格式 YYYY-MM-DD,注意01的0也要有
## time
time.fromisoformat("12:45:10") # 字符转时间,仅支持格式HH:MM:DD
执行结果:
datetime.datetime(2019, 12, 31, 15, 36, 17, 324520)
datetime.datetime(2020, 1, 1, 0, 0)
datetime.datetime(2020, 1, 1, 12, 0)
datetime.date(2019, 12, 31)
datetime.date(2024, 5, 26)
datetime.date(2020, 1, 1)
datetime.time(12, 45, 10)
类属性
datetime每一个类里面的参数,都是可以通过获取类属性的方式单独取出来的。
date:year、month、daytime:hour、minute、second、mircoseconddatetime:year、month、day、hour、minute、second、mircoseconddt = datetime.today()
dt
dt.year
dt.month
dt.day
dt.hour
dt.minute
dt.second
dt.microsecond
执行结果:
2019
12
31
15
22
40
354681
使用方法
replace()
修改替换时间中的时间参数,适用于三种类,例如:
dt = datetime.now()
dt
dt.replace(year=2020,day=15,hour=12)
执行结果:
timetuple()
返回time模块中的时间元组,适用于datetime对象和date对象,不适用于time对象,例如:
dt = datetime.now()
dt.timetuple()
执行结果:
datetime.datetime(2019, 12, 31, 15, 27, 5, 882867)
time.struct_time(tm_year=2019, tm_mon=12, tm_mday=31, tm_hour=15, tm_min=27, tm_sec=5, tm_wday=1, tm_yday=365, tm_isdst=-1)
toordinal()
返回ISO公历序数,即从公元0年1月1日起到目标日期的天数。适用于datetime对象和date对象,不适用于time,例如:
dt = datetime.now()
dt.toordinal()
d = date.today()
d.toordinal()
执行结果:
737424
737424
timestamp()
返回时间戳,即从公元1970年1月1日0时0分0秒起,到目标时间的秒数。仅适用于datetime对象,不适用于time对象和date对象,例如:
dt = datetime.now()
dt.timestamp()
执行结果:
1577777225.882867
weekday()
返回目标日期的工作日,0代表星期一,6代表星期日,适用于datetime对象和date对象,不适用于time对象,例如:
dt = datetime.now()
dt.weekday()
d = date.today()
d.weekday()
执行结果:
1
1
isoweekday()
返回目标日期的工作日,1代表星期一,7代表星期日,它和weekday的区别仅仅在于起始序数的不同,适用于datetime对象和date对象,不适用于time对象,例如:
dt = datetime.now()
dt.isoweekday()
d = date.today()
d.isoweekday()
执行结果:
2
2
isocalendar()
返回一个包含目标日期的年份、在一年中的第几周、周几三个元素在内的元组,适用于datetime对象和date对象,不适用于time,例如:
dt = datetime.now()
dt.isocalendar()
d = date.today()
d.isocalendar()
执行结果:
(2020, 1, 2)
(2020, 1, 2)
isoformat(sep ='T',timespec ='auto')
返回一个标准化的时间字符串,适用三种类;datetime对象使用时返回完整的字符串,日期和时间的分隔部分默认为字符“T”,可设定;date对象使用时只返回日期部分的字符串,time对象使用时只返回时间部分的字符串,例如:
dt = datetime.now()
dt.isoformat() # 默认以字符“T”分隔日期和时间
dt.isoformat(sep=" ") # 以空格“ ”分隔日期和时间
d = date.today()
d.isoformat() # 日期部分
t = datetime.now().time()
t.isoformat() # 时间部分
执行结果:
'2019-12-31T15:27:05.882867'
'2019-12-31 15:27:05.882867'
'2019-12-31'
'15:27:05.882867'
strftime(format)
返回表示日期和时间的字符串,由明确的格式字符串控制,适用三种类。
详细的字符串格式如下所示:
格式含义示例%a工作日(缩写)Sun, Mon, …, Sat%A工作日(全称)Sunday, Monday, …, Saturday%w以十进制数表示的工作日,其中0是星期日,6是星期六。0,1,…,6%d月份中的一天,十进制数字表示。01,02,…,31%b月份,缩写名称。Jan, Feb, …, Dec%B月份,全名。January, February, …, December%m月份,十进制数字01,02,…,12%y年份(无世纪的年份,后两位),十进制数字。00,01,…,99%Y年份(四位完整),十进制数字。0001,0002,…,2013,2014,…,9998,9999%H小时(24小时制),十进制数字。00,01,…,23%I小时(12小时制)01,02,…,12%pAM或PMAM, PM%M分钟,十进制数字。00,01,…,59%S秒,以零填充的十进制数。00,01,…,59%f微秒,以零填充的十进制数。000000,000001,…,999999%zUTC偏移量的格式 ±HHMM[SS[.ffffff]](empty), +0000, -0400, +1030, +063415, -030712.345216%Z时区名称(empty), UTC, EST, CST%j一年中的一天,十进制数字。001,002,…,366%U一年中的第几周(星期日为一周的第一天),以零填充的十进制数表示。以周六所在年份为基准。00,01,…,53%W一年中的第几周(星期一为一周的第一天),以零填充的十进制数表示。以周日所在年份为基准00,01,…,53%c日期和时间Tue Aug 16 21:30:00 2019%x日期12/30/19%X时间17:24:13%%文字'%'字符。%%G年份,以零填充的十进制数表示。0001,0002,…,2013,2014,…,9998,9999%u工作日,十进制数字,其中1为星期一。1,2,…,7%V一年中的第几周(星期一为一周的第一天)。第01周是包含1月4日的一周。01,02,…,53
示例:
dt = datetime.now()
d = dt.date()
t = dt.time()
dt.strftime("%Y-%m-%d") # 常用日期一
d.strftime("%Y/%m/%d") # 常用日期二
t.strftime("%H:%M") # 时分
t.strftime("%p %I:%M") # 12时制时分
dt.strftime("%Y%m%d%H%M%S%f")+str(".txt") # 文件名
print("现在是北京时间{0}年{1}月{2}日,今天是{0}年的第{3}周,是{0}年的第{4}天".format(dt.strftime("%Y"),dt.strftime("%m"),dt.strftime("%d"),dt.strftime("%U"),dt.strftime("%j")))
执行结果:
'2019-12-31'
'2019/12/31'
'15:27'
'PM 03:27'
'20191231152705882867.txt'
现在是北京时间2019年12月31日,今天是2019年的第52周,是2019年的第365天
strptime(date_string, format)
将字符串解析为datetime指定格式的对象,由明确的格式字符串控制,与strftime方法相对应。其内部还是先调用的time模块中的striptime方法,获取struct_time对象,再利用struct_time对象中的年月日时分秒信息构建datetime对象。
strftime 即 string format time,用来将时间格式化成字符串
strptime 即string parse time,用来将字符串解析成时间。
strptime方法只适用于datetime对象。例如:
datetime.strptime("2020-01-01 12:00:00","%Y-%m-%d %H:%M:%S")
执行结果:
datetime.datetime(2020, 1, 1, 12, 0)
以上介绍的方法中:
只适用于类datetime的方法:timestamp( )、strptime( )适用三种类的方法:replace( )、isoformat( )、strftime( )类timedelta
在日常的实际使用中,我们经常需要对日期进行比较和加减运算。得益于python的操作符重载能力,python中可以方便地对date对象之间,或者datetime对象之间进行大小比较和减法(-)操作。
需要注意的是,这里仅限于同类对象之间的比较和减法运算,而且,不包括与time模块对象的比较和运算。datetime模块中的三个类,time对象仅能与同类做比较,不能进行任何运算,而date对象和datetime对象是可以和同中类型对象做减法运算的。
示例一:
## time对象只能同类做比较
time(21,2,4) >time(20,3,2)
# output1: True
## datetime对象可以比较,也可以做运算
dt = datetime(2019, 12, 31, 15, 22, 40, 354681)
dt - datetime(2019,1,1,0,0,0)
dt > datetime(2020,1,1,0,0,0)
# output2: datetime.timedelta(days=363, seconds=62653, microseconds=913011)
# output3: False
## date对象可以比较,也可以做运算
date(2020,1,1) - date(2019,1,1)
date(2020,1,1) > date(2019,12,31)
# output4: datetime.timedelta(days=365)
# output5: True
datetime模块中三种对象的比较运算对比:
类能否同类比较能否同类作运算(仅减法)能否和timedelta类进行运算datetime能能能date能能能time能不能不能
从示例中可以看到,datetime对象和date对象同类中做减法返回的结果是datetime.timedelta对象,而这个就是datetime模块中专门用于时间运算的类。个人认为,类timedelta是datetime模块中最有价值的一部分,需要重点学习一下。
timedelta参数转换
timedelta对象表示持续时间,两个日期或时间之间的差,它一共有7个参数可以用来定义timedelta对象。
timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)但不是所有参数都会保留显示,timedelta对象定义后,内部仅存储天(day),秒(seconds)和微秒(microseconds)。其余参数将按以下单位换算转换为天、秒、微秒:
毫秒转换为1000微秒。一分钟转换为60秒。一个小时转换为3600秒。一周转换为7天。相应的转换公式为:
days = days + weeks * 2 = 64seconds = seconds + milliseconds/1000 + minutes * 60 + hours * 3600microseconds= microseconds它们之间的装换
1 days = 86400 seconds1 seconds = 1000000 microseconds示例:
t = timedelta(50,27,10,29000,7,8,2)
# output: datetime.timedelta(days=64, seconds=29276, microseconds=10)
timedelta对象的简单运算
timedelta对象进行多种合理的时间运算,如timedelta对象间加减法,timedelta对象与数值的乘除法运算。
示例二:
## timedelta对象可以进行的运算
t = timedelta(50,27,10,29000,7,8,2)
d = timedelta(5,3,234,324,35,16,0)
t + d # timedelta对象间加减法
t - d
t * 2.3 # timedelta对象与数值乘除法
t / 2.8
示例三:
t // 2 # timedelta对象整除,返回timedelta对象
t // d # timedelta对象间整除,返回整数
t / d # timedelta对象间相除,返回float
t % d # timedelta对象间相除取余数,返回timedelta对象
divmod(t,d) # 求模
执行结果:
datetime.timedelta(days=32, seconds=14638, microseconds=5)
11
11.305345573308651
datetime.timedelta(days=1, seconds=63739, microseconds=433436)
(11, datetime.timedelta(days=1, seconds=63739, microseconds=433436))
可以用total_seconds()方法获得一个timedelta对象的秒数表示,可用于和时间戳进行运算。
timedelta.total_seconds(t)
t.days * 86400 + t.seconds + t.microseconds/1000000
# output1: 5558876.00001
# output2: 5558876.00001
正负值
timedelta对象含有三个属性:days,seconds, microseconds,days属性可以取负值,另外两个属性都只能是正值。示例
t = timedelta(days=27,seconds=47283,microseconds=123942)
t
n = -t # 去t的负数
n
t + n # 等于0
t.seconds + n.seconds # 秒数相加等于86399
t.microseconds + n.microseconds # 微秒相加等于1,000,000
# timedelta对象也可以使用abs()函数求绝对值
abs(n) # 返回对应正数的timedelta对象
执行结果:
datetime.timedelta(days=27, seconds=47283, microseconds=123942)
datetime.timedelta(days=-28, seconds=39116, microseconds=876058)
datetime.timedelta(0)
86399
1000000
datetime.timedelta(days=27, seconds=47283, microseconds=123942)
timedelta对象的计算运用
前面提到的只是timedelta对象的一些基础内容,实际使用上更多的是和date对象或者datetime对象进行计算,计算主体是date对象或者datetime对象,timedelta对象作为辅助。
示例:
# date运算
date(2020,1,1) - timedelta(days=100)
date(2020,1,1) + timedelta(days=100)
# datetime运算
dt = datetime(2020,2,22,20,2,2)
dt
dt + timedelta(days=20,seconds=4023)
dt - timedelta(days=20,seconds=4023)
执行结果:
# date运算结果
datetime.date(2019, 9, 23)
datetime.date(2020, 4, 10)
# datetime运算结果
datetime.datetime(2020, 2, 22, 20, 2, 2)
datetime.datetime(2020, 3, 13, 21, 9, 5)
datetime.datetime(2020, 2, 2, 18, 54, 59)
通过以上对datetime模块的各种对象的详细介绍,相信足以对它的各种操作有了比较完整的了解,这些都是基础的示例运用,更进一步的使用要通过实际运用中各种不一样的需求来实践。