Python 並沒有提供時間的資料型態 (像 int, float, str, tuple, list 等那樣), 而是在標準函式庫中以 time, datetime, 與 calender 這三個模組來處理日期與時間資訊. 本篇測試並整理 time 模組的用法.
time 模組主要是依賴底層的 C 函式庫來取得系統的時鐘資訊與處理器的執行時間, 還提供了基本的剖析與字串格式化功能. 在 MicroPython 的物聯網應用中, time 模組的 sleep() 函式常用來控制致動器 (actuator) 的延遲時間.
本篇主要是我閱讀下列書籍時隨手測試所做的整理 :
- Python 零基礎入門班 (碁峰 2018, 文淵閣工作室)
- 增壓的 Python-讓程式碼進化到全新境界 (碁峰 2020)
- Python Bible 自學聖經 (碁峰 2020, 文淵閣工作室)
# Python 學習筆記 : 檢視物件成員與取得變數名稱字串的方法
使用 time 模組之前須先用 import 匯入 :
>>> import time
>>> members.list_members(time)
altzone <class 'int'>
asctime <class 'builtin_function_or_method'>
clock <class 'builtin_function_or_method'>
ctime <class 'builtin_function_or_method'>
daylight <class 'int'>
get_clock_info <class 'builtin_function_or_method'>
gmtime <class 'builtin_function_or_method'>
localtime <class 'builtin_function_or_method'>
mktime <class 'builtin_function_or_method'>
monotonic <class 'builtin_function_or_method'>
monotonic_ns <class 'builtin_function_or_method'>
perf_counter <class 'builtin_function_or_method'>
perf_counter_ns <class 'builtin_function_or_method'>
process_time <class 'builtin_function_or_method'>
process_time_ns <class 'builtin_function_or_method'>
sleep <class 'builtin_function_or_method'>
strftime <class 'builtin_function_or_method'>
strptime <class 'builtin_function_or_method'>
struct_time <class 'type'>
thread_time <class 'builtin_function_or_method'>
thread_time_ns <class 'builtin_function_or_method'>
time <class 'builtin_function_or_method'>
time_ns <class 'builtin_function_or_method'>
timezone <class 'int'>
tzname <class 'tuple'>
常用函式如下表 :
time 模組常用函式 | 說明 |
time() | 傳回自初始計時 1970/1/1 至今的系統秒數時戳 (精確至微秒) |
localtime([sec]) | 傳回目前時間或指定時戳秒數 sec 的 struct_time 物件 |
ctime([sec]) | 傳回目前時間或指定時戳秒數 sec 的時間字串 |
sleep(sec) | 程序暫停執行 sec 秒 (可為浮點數) |
process_time() | 傳回程序執行至此之時戳 |
mktime(t) | 將傳入之 struct_time 物件或元組 t 轉成時戳傳回, 乃 localtime() 反函數 |
strftime(format [, t]) | 以格式化字串顯示 localtime() 傳回之時戳 t |
Python 處理時間的一個 tick 是微秒 (百萬分之一秒), 呼叫 time() 函式所傳回的時戳是一個浮點數, 單位為秒, 此時戳為自初始計時日 1970/1/1 日零時零分零秒開始計算到目前的秒數, 例如 :
>>> time.time()
1661485827.710501
這表示自 1970/1/1 日至目前已過了 1661485827.710501 秒. 這時戳必須經過換算才知道是幾年幾個月幾日幾時幾分幾秒, 看起來似乎實用性不高, 但其實它是一個基礎函式, 主要是用來給 time 模組內其他函式計算之用.
localtime([sec]) 函式會傳回目前或指定時戳秒數之 struct_time 物件, 例如 :
>>> local=time.localtime()
>>> local
time.struct_time(tm_year=2022, tm_mon=8, tm_mday=26, tm_hour=14, tm_min=51, tm_sec=3, tm_wday=4, tm_yday=238, tm_isdst=0)
>>> type(local)
<class 'time.struct_time'>
struct_time 物件屬性 | 說明 |
tm_year | 年 |
tm_mon | 月 (1~12) |
tm_mday | 日 (1~31) |
tm_hour | 時 (0~23) |
tm_min | 分 (0~59) |
tm_sec | 秒 (0~59) |
tm_wday | 一星期中的第幾天 (0~6, 0=星期一, 6=星期日) |
tm_yday | 一年中的第幾天 (1~366) |
tm_isdst | 是否在日光節約時間, 0=否, 1=是 |
可以透過 struct_time 物件之屬性取得日期時間資訊, 例如 :
>>> local.tm_year # 年
2022
>>> local.tm_mon # 月
8
>>> local.tm_mday # 日
26
>>> local.tm_hour # 時
14
>>> local.tm_min # 分
51
>>> local.tm_sec # 秒
3
>>> local.tm_wday # 周
4
>>> local.tm_yday # 年中之日
238
>>> local.tm_isdst # 是否在日光節約時間
0
因為 localtime() 的傳入參數是時戳秒數, 故可以將 time.time() 的秒數傳給 localtime() :
>>> time.localtime(time.time())
time.struct_time(tm_year=2022, tm_mon=8, tm_mday=26, tm_hour=19, tm_min=38, tm_sec=10, tm_wday=4, tm_yday=238, tm_isdst=0)
另一個函式 ctime() 功能與 localtime() 相同, 差別是 ctime() 的傳回值是可讀性較高的時間字串 (但時間精度僅到秒), 預設傳回目前時間, 例如 :
>>> time.ctime() # 未傳入參數預設為目前時間
'Fri Aug 26 19:47:55 2022'
也可以將時戳秒數傳入 ctime() 轉成時間字串, 例如 :
>>> time.ctime(1661514622) # 傳入時戳秒數
'Fri Aug 26 19:50:22 2022'
sleep() 函式會讓程序暫停指定之秒數進入休眠狀態, 等過了這時間再繼續往下執行, 在互動環境下提示號會在這段時間過後才會出現 :
>>> time.sleep(10) # 等待 10 秒
>>>
process_time() 函式會傳回程序執行時的時戳, 前後兩次呼叫 process_time() 之差值即為程序執行所花的時間, 此函式是 Python 3.3 版新增的, 用來取代舊版的 clock(), 在 Python 3.8 版中已正式移除 clock() 了.
process_time() 與 time() 都可以用來計算程式執行時間, 但 time() 是牆上時鐘 (wall clock), 包含了 sleep() 的時間; 而 process_time() 則是程序時鐘, 不包含 sleep() 秒數, 參考 :
我把該文之範例改編成如下程式碼 :
# elapsed_time.py
import time
process_start=time.process_time()
time_start=time.time()
i=0
for i in range(100000000):
i += 1
time.sleep(5)
process_end=time.process_time()
time_end=time.time()
print("process_time() elapsed : %f" % (process_end - process_start))
print("time() elapsed : %f" % (time_end - time_start))
結果如下 :
>>> %Run elapsed_time.py
process_time() elapsed : 9.609375
time() elapsed : 14.626676
可見呼叫 process_time() 不會將 time.sleep() 休眠時間算進去. 如果將 time.sleep() 這列註解掉後重新執行, 結果會差不多 :
>>> %Run test2.py
process_time() elapsed : 9.203125
time() elapsed : 9.200775
接下來看 mktime(t) 函式. 它是 localtime() 的反函式, 其傳入參數有兩種, 一是 time_struct 物件, 例如 local_time() 的傳回值就是此種物件, mktime() 的傳回值為傳入參數所代表的時戳 :
>>> time.mktime(time.localtime())
1661653676.0
將 localtime() 傳回之 time_struct 物件傳入 mktime() 會得到該物件所代表之時戳.
第二種傳入參數是一個 9 元素的 tuple (一定要 9 個元素, 少一個都不行, 前六個年月日時分秒決定傳回值, 後面三個元素可隨意填, 不影響傳回之時戳), 其元素依序是 time_struct 物件的屬性值, 例如 :
>>> time.localtime()
time.struct_time(tm_year=2022, tm_mon=8, tm_mday=28, tm_hour=10, tm_min=28, tm_sec=31, tm_wday=6, tm_yday=240, tm_isdst=0)
>>> time.mktime((2022, 8, 28, 10, 26, 31, 6, 240, 0))
1661653591.0
strftime(fomat [, t]) 函式用來將 localtime() 等函式傳回之時戳 t 轉成 format 字串所指定之格式, 如果沒有傳入時戳預設為目前時間, 可用之格式化字串 foormat 如下表 :
format 格式化字串 | 說明 |
%a | 星期的縮寫, 例如 Sun, Mon, Tue 等 |
%A | 星期的全寫, 例如 Sunday, Monday, Tuesday 等 |
%b | 月份的縮寫, 例如 Jan, Feb, Mar 等 |
%B | 月份的全寫, 例如 January, Feburary, March 等 |
%c | 本地之日期時間, 例如 'Sun Aug 28 13:17:18 2022' |
%d | 一個月中的第幾日 (1~31) |
%H | 24 小時制的時 (0~23), 例如 13 (下午一點) |
%I | 12 小時制的時 (0~12), 例如 01 (下午一點或凌晨一點) |
%j | 一年中的第幾日 (1~366) |
%m | 數字月份 (1~12) |
%M | 分鐘 (0~59) |
%p | 上午 ('AM') 或下午 ('PM') |
%S | 秒 (0~59) |
%U | 一年中的第幾周 (0~53), 第一個星期日之前為第0 周 (週日為一周之始) |
%w | 一周中的第幾天 (0~6), 週日為 0 |
%W | 一年中的第幾周 (0~53), 第一個星期一之前為第0 周 (週一為一周之始) |
%x | 本地之日期, 格式=月/日/年(兩位), 例如 '08/28/22' |
%X | 本地之日期, 格式=時:分:秒, 例如 '14:14:48' |
%y | 無世紀之年份 (2 位數), 例如 '22' (表示 2022 年) |
%Y | 有世紀之年份 (4 位數), 例如 '2022' (表示 2022 年) |
%z | 相對於 GMT 的時區偏移值 (24 小時制), 例如台灣是 '+0800' 表示 GMT+8 |
%Z | 時區名稱 (已棄用) |
%% | 顯示 '%' 字元 |
例如 :
>>> time.strftime('%a')
'Sun'
>>> time.strftime('%A')
'Sunday'
>>> time.strftime('%b')
'Aug'
>>> time.strftime('%B')
'August'
>>> time.strftime('%C')
'20'
>>> time.strftime('%c')
'Sun Aug 28 13:17:18 2022'
>>> time.strftime('%d')
'28'
>>> time.strftime('%H')
'13'
>>> time.strftime('%I')
'01'
>>> time.strftime('%j')
'240'
>>> time.strftime('%m')
'08'
>>> time.strftime('%M')
'04'
>>> time.strftime('%p')
'PM'
>>> time.strftime('%U')
'35'
>>> time.strftime('%x')
'08/28/22'
>>> time.strftime('%X')
'14:14:48'
>>> time.strftime('%y')
'22'
>>> time.strftime('%Y')
'2022'
>>> time.strftime('%Z')
'¥x¥_¼Ð·Ç®É¶¡'
>>> time.strftime('%z')
'+0800'
>>> time.strftime('%%')
'%'
注意, 格式 '%Z' 傳回的時區是亂碼, 因為那是 byte 資料, 參考下面這篇文章用 encode('latin1') 可顯示 16 進位編碼, 但接著用 decode('utf-8') 或 decode('utf-8') 卻出現錯誤 :
>>> time.strftime('%Z').encode('latin1')
b'\xa5x\xa5_\xbc\xd0\xb7\xc7\xae\xc9\xb6\xa1'
>>> time.strftime('%Z').encode('latin1').decode('utf8')
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa5 in position 0: invalid start byte
不過此格式字串已被棄用了.
參考 :
沒有留言:
張貼留言