作者: dameng
本篇介绍python自带的时间与日期包的使用,不涉及任何需要额外安装的包。
python中的时间日期等对象datetime
date
time X2
timestamp
timezone
timedelta
这里面我们主要使用的是datetime,而timestamp则是另一种展现形式,也就是一个数字
datetime 的基本表达
如果我们有这么一个时间戳 2019-01-01 00:00:00,有日期,有时间,所以可以直接对应的就是日期时间对象datetime了,在python中可以这样声明datetime(2019,1,1, 0,0,0),如果直接将这个对象用print输出,其会输出2019-01-01 00:00:00。
从字面意义理解datetime对象是由date和time两个部分组成的,如果设计的足够直观,够按照这个推理,一个date对象和一个time对象应该是可以构造一个datetime, 只是稍微有些不够直观的是,你需要使用combine方法来构造新的datetime,而不是以构造参数的方式传入date和time
d = date(2019,1,1)
print(d)
t = time(0,0,0)
print(t)
# dt = datetime.datetime(date=d, time=t)
dt = datetime.datetime.combine(d, t)
print(dt)
上面的输出如下,
2019-01-01
00:00:00
2019-01-01 00:00:00
另外,很直观的,你可以使用datetime获取相关的一些参数,比如年月日,时分秒
print("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second))
print(dt.weekday())
print(dt.isoweekday())
print(dt.isocalendar())
print(dt.date())
print(dt.time())
其会输出, 要注意的是,比如今天是星期四,isoweekday输出的是4,weekday输出的是3
2019-04-04 17:19:05
3
4
(2019, 14, 4)
2019-04-04
17:19:05.766999
时间与数字
如果你使用dir来查看datetime的方法,应该能观察到其包含有一个timestamp, timestamp是一个浮点型的小数,表示当前时间到utc时间1970.01.01凌晨相距的秒数。
和timestamp不同,python的time包中还有一个time对象,当我们调用time.time()会返回一个float形态的数值,其精度比timestamp更高(多一位)。如果是需要更高的精度,可以使用time.time_ns()获取纳秒级别的数值, 不过此时返回的是整数形态,精度比timestamp高三位!
# timestamp的底层实现
(dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()
将时间转换成数字有几个优势,但是具体还要按需求来定,更小的存储
方便的比较与计算(当然本身datetime对象也是支持的,但是某些需要引入timedelta对象)
格式相对统一(因为简单)
如果要使用timestamp完成时间的比较与加减,直接计算就好了。但是如果要使用timestamp就会稍微麻烦一些,datetime目前支持如下几种
datetime2 = datetime1 + timedelta
datetime2 = datetime1 - timedelta
timedelta = datetime1 - datetime2
datetime1 < datetime2Compares datetime to datetime.
要注意的是datetime和timedelta做加减后的对象依旧是datetime
datetime对象之间可以直接比较
datetime和datetime相减,得到一个timedelta对象,同时小减大,将得到负数
datetime不可以和datetime相加
比如要计算当前时间的8小时后,就是
n = datetime.datetime.now()
m = n + datetime.timedelta(hours=8)
print(m, type(m))
print(m
其会输出
2019-04-09 02:36:37.956798
False True
万恶之源
要注意的是,像这样datetime(2019,1,1, 0,0,0)声明的一个对象是没有时区信息的,每一个datetime对象都有一个tzinfo的属性,而刚刚生成的这个对象的tzinfo是None。如果要声明一个带有时区信息的datetime对象需要先声明一个时区, 而这个时区就是一个timezone对象,可以通过timedelta来完成构造
e8zone = timezone(timedelta(hours=8), 'Asia/Shanghai')
d = datetime(2019,1,1, 0,0,0, tzinfo=e8zone)
print(d)
而此时的输出是
2019-01-01 00:00:00+08:00
可以看到和前面相比多出来了+08:00的信息表示东八区, 如果是一个没有timezone的datetime对象,时区部分则不会输出。
另外,你还可以定制化datetime对象的输出
f = d.strftime("%Y-%m-%d%H:%M:%S.%f%Z")
print(f)
此时,会输出
2019-01-01 00:00:00.000000 Asia/Shanghai
此时,%Z输出了文字形式的时区,如果想要类似+0800形式的时区格式,可以换成%z时区不只是+8,-8这样的,还有不规则的时区比如加拿大纽芬兰的时区
e3mzone = timezone(timedelta(hours=-3, minutes=-30), 'Canada/Newfoundland')
d = datetime.datetime(2019,1,1, 0,0,0, tzinfo=e3mzone)
print(d)
会输出
2019-01-01 00:00:00+08:00
而当我们替换时区时,默认的python包并不会自动转换
e3mzone = timezone(timedelta(hours=-3, minutes=-30), 'Canada/Newfoundland')
d = datetime.datetime(2019,1,1, 0,0,0, tzinfo=e3mzone)
print(d)
e8zone = timezone(timedelta(hours=8), 'Asia/Shanghai')
d = d.replace(tzinfo=e8zone)
print(d)
会输出
2019-01-01 00:00:00-03:30
2019-01-01 00:00:00+08:00比时区更加复杂的是夏时制(夏令时)
夏时制(夏令时),又称日光节约时间,是一种在夏季月份牺牲正常的日出时间,而将时间调快的做法。通常使用夏时制的地区,会在接近春季开始的时候,将时间调快一小时,并在秋季调回正常时间。实际上,夏时制会造成在春季转换当日的睡眠时间减少一小时,而在秋季转换当日则会多出一小时的睡眠时间。 1895年,乔治·哈德逊提出了夏时制的概念。
在python3.6之后,python的datetime引入了一个新的参数fold,用来折叠这个时间.
举例来说,比如德国时间会在29th of October 2017 at 3 AM回调到 2 AM, 那么同样是 2:30 AM, 就会有两个了,一个是会调前的,一个是回调后的。fold=0 和 1 则分别对应了这两种时间。