文章目录
概念
- epoch:系统记录的时间起点,对于windows,unix系统,其为January 1, 1970, 00:00:00 (UTC)。在计时中一般会记录从这个点开始过了多少秒,这就是当前的时间。
- seconds since the epoch:从epoch开始流逝的秒数。闰秒不会记录在内。
- GMT:格林尼治标准时间。这是以英国格林尼治天文台观测结果得出的时间,这是英国格林尼治当地时间,这个地方的当地时间过去被当成世界标准的时间。
- UT:世界时。根据原子钟计算出来的时间,可以认为是绝对的标准时间。
- UTC:协调世界时。因为地球自转越来越慢,每年都会比前一年多出零点几秒,每隔几年协调世界时组织都会给世界时+1秒(这也是闰秒的由来),让基于原子钟的世界时和基于天文学(人类感知)的格林尼治标准时间相差不至于太大。并将得到的时间称为UTC,这是现在使用的世界标准时间。协调世界时是世界时和格林尼治标准时间之间的折衷。协调世界时不与任何地区位置相关,也不代表此刻某地的时间,所以在说明某地时间时要加上时区也就是说GMT并不等于UTC,而是等于UTC+0,只是格林尼治刚好在0时区上。GMT = UTC+0
- DST:夏令时。有的国家为了充分利用光照节约资源会人为调整自己的时间来间接改变人们的起居生活方式,但后来有的国家认为这样会影响人们的心理健康。中国曾经使用过夏令时,现以弃用。夏令时不同地方有不同的政策,在库调用底层的C代码时会有一个记录当地夏令时的表。
一、time库唯一的对象:time.struct_time
time.struct_time是time库唯一的对象,这个对象有一个named tuple 接口,通过它可以访问里面存储的数据,就跟C语言里面的struct一样,故同时也是它的重要数据类型。
1.这个数据结构是什么样的?如何访问他?
有两种方式访问
- 通过index
- 通过attribute name
index | Attribute | Values |
---|---|---|
0 | tm_year | 年份,如2021 |
1 | tm_mon | range [1, 12] |
2 | tm_mday | range [1, 31] |
3 | tm_hour | range [0, 23] |
4 | tm_min | range [0, 59] |
5 | tm_sec | range [0, 61] |
6 | tm_wday | range [0, 6], Monday is 0 |
7 | tm_yday | range [1, 366] |
8 | tm_isdst | 是否存在夏令时0, 1 or -1(0为否,1为是,-1为未知) |
N/A | tm_zone | 时区名称的缩写 |
N/A | tm_gmtoff | 日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数 |
其中最后一个啥意思我也不懂哈哈。下面我们假设已经获取了这个对象,如何访问它呢?
import time
gmt_tm = time.gmtime()
print(gmt_tm) # time.struct_time(tm_year=2021, tm_mon=8, tm_mday=22, tm_hour=3, tm_min=7, tm_sec=0, tm_wday=6, tm_yday=234, tm_isdst=0)
print(gmt_tm[0]) # 2021
print(gmt_tm.tm_year) # 2021
二、time库的基础函数
time库里面函数还是挺多的,但是有的函数只能在unix系统上用,有一些函数以及参数涉及到时区转换什么的,看了官方文档感觉这些东西太过于专业了,平时做一些数据分析任务或者是测试程序运行时间,根本用不到这些复杂的概念,所以这篇文章选择先介绍一些基础的函数,然后根据任务去介绍常用的函数。
1.time.time()和time.time_ns()
time.time()返回时间戳,以秒为单位,也即seconds since the epoch
time.time_ns() 返回时间戳,以纳秒为单位
这里返回的时间其实是UTC的时间,而不是你计算机的本地时间,格式是时间戳
import time
print(time.time()) # 1629615463.5170913
print(time.time_ns()) # 1629615463517091300
2.time.gmtime([secs])
获取UTC时间,但是格式是struct_time
input:seconds since the epoch,如果没有,默认用time.time()返回结果
output:a struct_time in UTC,dst flag is always zero
import time
print(time.gmtime()) # time.struct_time(tm_year=2021, tm_mon=8, tm_mday=22, tm_hour=7, tm_min=3, tm_sec=40, tm_wday=6, tm_yday=234, tm_isdst=0)
3.time.localtime([secs])
获取本地时间
input:seconds since the epoch,如果没有,默认用time.time()返回结果
output:a struct_time,如果当地使用了夏令时,dst flag set to 1
import time
print(time.localtime()) #time.struct_time(tm_year=2021, tm_mon=8, tm_mday=22, tm_hour=13, tm_min=38, tm_sec=51, tm_wday=6, tm_yday=234, tm_isdst=0)
上述代码在中国运行,中国没有使用夏令时,所以tm_isdst=0。
4.time.mktime(t)
该函数功能和time.localtime([secs])恰好相反
input:struct_time,或9元组,一定要表示的是当地时间,而不是UTC时间
output:返回时间戳
import time
cur_tm = time.localtime()
print(cur_tm) # time.struct_time(tm_year=2021, tm_mon=8, tm_mday=22, tm_hour=13, tm_min=52, tm_sec=51, tm_wday=6, tm_yday=234, tm_isdst=0)
print(time.mktime(cur_tm)) # 1629611571.0
5.time.sleep(secs)
休眠给定时间,secs可以是整数也可以是浮点数。
看官方文档解释,准确地来说是至少休眠这么长时间,因为即使你休眠结束了,系统这时候可能在处理其他任务不会及时回到你这个任务中。
三.根据任务介绍函数
1.如何进行日期格式的转换?
固定格式转换time.asctime([t])和time.ctime([secs])
(1)time.asctime([t])
将一个元组或者是struct_time对象改变格式,变成如
'Sun Jun 20 23:21:05 1993'
的固定格式,output类型是str。要注意的是月份占两个字符,各信息之间用空格连接,如果月份只有一位,就如下所示:
'Wed Jun 9 04:26:40 1993'
如果不提供参数,则默认使用time.localtime()返回的参数。
import time
gmt_tm = time.gmtime()
print(time.asctime(gmt_tm)) # 'Sun Aug 22 03:07:00 2021'
除了struct_time输入,也可以使用9元组作为输入
import time
print(time.asctime((2021,8,22,13,38,51,6,234,0))) # 'Sun Aug 22 13:38:51 2021'
(2)time.ctime([secs])
功能和time.asctime([t])一样,只是输入参数不一样,输入的是 seconds since the epoch,如果没有输入参数,就会调用time.time()的返回值。因为功能相近,故time.ctime(time.time()) =time.asctime(time.localtime())
import time
print(time.ctime(time.time()) == time.asctime(time.localtime())) # True
自定义格式转换
(1)time.strftime(format[, t])
用于将本地时间转换成给定格式的字符串
input:format格式控制字符串,另外一个可选,struct_time或者元组,如果不给第二个,默认用time.localtime()返回的
output:按照格式控制字符串样式的 时间字符串
格式控制表参见 官网.
import time
loc_tm = time.strftime('%Y-%m-%d %H:%M:%S')
print(loc_tm) # '2021-08-22 15:35:03'
time库是不支持输出微秒级别的时间,但是datetime库好像可以,后面也会出一期datetime库的笔记。
(2)time.strptime(string[, format])
跟time.strftime(format[, t])的功能刚好相反,将string按照指定格式进行解析,并返回一个struct_time.
默认格式是"%a %b %d %H:%M:%S %Y",这是time.ctime()函数输出的格式
import time
loc_tm = '2021-08-22 15:35:03'
tm = time.strptime(loc_tm,'%Y-%m-%d %H:%M:%S')
print(tm)
# time.struct_time(tm_year=2021, tm_mon=8, tm_mday=22, tm_hour=15, tm_min=35, tm_sec=3, tm_wday=6, tm_yday=234, tm_isdst=-1)
2.如何使用计时器来对程序运行时间进行计时?
这部分内容参考了另外一篇博客传送门
time库中有多种可以用于程序计时的函数,他们各不相同,有的精度不同,有的是计数单调增加(时间值不会相同),有的则是机制不同。
我们要对一个程序运行时间计时,其实就是需要一个差值而已,程序开始和结束两个时间是多少并不重要,因此不一定要求程序开始的时间记录的一定要是UTC时间。
先来看看可以有多少种计时的函数
- time.time() 返回系统unix时间
- time.monotonic() monotonic时间是指系统启动后从0开始递增的时间,它不会因为我们调整系统时间而发生回调这种情况。
- time.perf_counter() 这个计时器记录的是python解释器启动后经过的时间。
- time.process_time()
- time.thread_time()
由于个人水平所限,对多线程没有什么概念,所以time.thread_time()的分析留到未来。
(1)获取各个clock的信息
time库提供了函数time.get_clock_info(name)以供查询各个clock的信息,name可以是下面的任意一个:
'time'
'monotonic'
'perf_counter'
'process_time'
'thread_time'
注意,查询到的值会根据设备的不同而不同,不同的设备、系统可能会提供不同的精度,底层的C代码也可能会演进,这个其实可以理解。我的CPU是i7-8750H
经过查询后可以总结得到如下的一个表格:
定时器类型 | djustable | implementation | monotonic | resolution |
---|---|---|---|---|
time.time() | True | GetSystemTimeAsFileTime() | False | 0.015625 |
time.monotonic() | False | GetTickCount64() | True | 0.015625 |
time.perf_counter() | False | QueryPerformanceCounter() | True | 1e-07 |
time.process_time() | False | GetProcessTimes() | True | 1e-07 |
time.thread_time() | False | GetThreadTimes() | True | 1e-07 |
adjustable: True表示该时间可以由系统管理员进行更改,比如你手动设置时间
implement:表示该方法参数经由系统底层C函数获取
monotonic:True表示时间不可以回退,反之
resolution:表示时间精度,类似于频率
(2)使用time.time()或time.time_ns()进行计时
这个比较简单,time.time返回的是绝对时间,程序开始时记个时间,结束记个时间,一减就可以了,要注意的是在运行期间系统的时间不能改变。
(3)使用time.monotonic()或time.monotonic_ns()进行计时
使用绝对时间进行计数实际上没有什么必要,这个函数采用相对时间计数,而且得到的时间不会回退!不会受到系统时间更改的影响。
这个函数的主要功能是返回一个带小数点的秒数,这个秒数来自于一个随机的时钟。
import time
a = 0
start_time = time.monotonic()
for i in range(100000):
a += 1
end_time = time.monotonic()
print(f"the start time: {start_time},the end time: {end_time},total time:{end_time - start_time}")
# the start time: 22517.781,the end time: 22517.796,total time:0.014999999999417923
减的时候对于小数存储不精确,打印出来尾巴就很长,可以用time.monotonic_ns()解决这个问题。
import time
a = 0
start_time = time.monotonic_ns()
for i in range(100000):
a += 1
end_time = time.monotonic_ns()
print(f"the start time: {start_time},the end time: {end_time},total time:{end_time - start_time}")
# the start time: 22867187000000,the end time: 22867203000000,total time:16000000
(4)使用time.perf_counter()和time.perf_counter_ns()进行计时
它使用设备中时间分辨率最高的计时器去获得时间,根据上面的表也可以看到比time.monotonic()系列精确得多。它是会记录程序sleep的时间以及system-wide,这个system-wide我理解是这样的,系统不可能所有的资源都为我们这个程序分配,那么这个程序在现实这样的环境中运行到底耗费了多少时间,就是这个system-wide的意思。
import time
a = 0
start_time = time.perf_counter()
for i in range(100000):
a += 1
end_time = time.perf_counter()
print(f"the start time: {start_time},the end time: {end_time},total time:{end_time - start_time}")
# the start time: 8686.3120564,the end time: 8686.3244895,total time:0.012433100000635022
剩下的任务待完成。。。。。
因为个人对多进程和多线程了解不行,所以这部分先放着,以后有机会接触这些概念的时候再补充吧
- time.process_time()
- time.thread_time()
总结
time库对于一般使用者来说的话,上面的内容基本上就涵盖了,基本的应用就是时间的格式转换和程序运行计时了,后面会再学习datetime库。