time --- 時間相關函式¶
time 模組提供取得目前時間與日期、測量時間間隔以及延遲的函式。
時間紀元(Epoch):以 Alif 與 i.MX RT 為基礎的 OpenMV Cam 使用 POSIX 紀元,即 1970-01-01 00:00:00 UTC。以 STM32 為基礎的 OpenMV Cam 使用 2000-01-01 00:00:00 UTC 的紀元。紀元年份可在執行階段以 gmtime(0)[0] 來判定。
維護實際的日曆日期/時間:這需要即時時鐘(RTC)。在 OpenMV Cam 上,系統時間由 machine.RTC 物件提供。目前的日曆時間可用 machine.RTC().datetime(tuple) 設定,並由下列其中一種方式維護:
備用電池(在某些 OpenMV Cam 上為選用元件)。
網路時間協定,例如
ntptime(需要網路連線)。在每次上電時手動設定。RTC 通常會在軟重置之間維持,但若未裝設備用電池,斷電時便會遺失。
若未維護日曆時間,下列參照目前絕對時間的函式將不會如預期般運作。
函式¶
- time.gmtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]¶
- time.localtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]¶
將以紀元(見上文)起算的秒數所表示的時間 secs,轉換為一個 8 元組,內容為:
(year, month, mday, hour, minute, second, weekday, yearday)。若未提供 secs 或為 None,則使用 RTC 中的目前時間。gmtime()函式回傳以 UTC 表示的日期時間元組,而localtime()回傳以當地時間表示的日期時間元組。8 元組中各項目的格式為:
year 包含世紀(例如 2014)。
month 為 1-12
mday 為 1-31
hour 為 0-23
minute 為 0-59
second 為 0-59
weekday 為 0-6,對應週一至週日
yearday 為 1-366
- time.mktime(date_time_tuple: Tuple[int, int, int, int, int, int, int, int]) int¶
這是 localtime 的反函式。它的引數是一個完整的 8 元組,依 localtime 的方式表示一個時間。它回傳一個整數,即自時間紀元起算的秒數。
- time.sleep(seconds: float) None¶
睡眠指定的秒數。seconds 可以是浮點數,以睡眠不足一秒的時間。若需要更細緻或僅限整數的延遲,請使用
sleep_ms()與sleep_us()函式。呼叫
sleep()(包括sleep(0))保證會呼叫待處理的回呼函式。
- time.sleep_ms(ms: int) None¶
延遲指定的毫秒數,應為正數或 0。
此函式至少會延遲指定的毫秒數,但若必須進行其他處理(例如中斷處理常式或其他執行緒),則可能耗時更久。即使對 ms 傳入 0,仍允許進行這類其他處理。若需更精確的延遲,請使用
sleep_us()。呼叫
sleep_ms()(包括sleep_ms(0))保證會呼叫待處理的回呼函式。
- time.ticks_ms() int¶
回傳一個遞增的毫秒計數器,其參考點任意,並在達到某個值後回繞。
回繞值並未明確公開,但為方便討論我們將其稱為 TICKS_MAX。這些值的週期為 TICKS_PERIOD = TICKS_MAX + 1。TICKS_PERIOD 保證為 2 的乘冪,但除此之外可能因移植版本而異。為求簡化,
ticks_ms()、ticks_us()、ticks_cpu()函式全部使用相同的週期值。因此,這些函式會回傳 [0 .. TICKS_MAX](含端點)範圍內的值,共 TICKS_PERIOD 個值。請注意只會使用非負值。大多數情況下,你應將這些函式回傳的值視為不透明值。對它們唯一可用的運算是下文所述的ticks_diff()與ticks_add()函式。註:直接對這些值執行標準數學運算(+、-)或關係運算子(<、<=、>、>=)會導致無效結果。先執行數學運算,再將其結果作為引數傳給
ticks_diff()或ticks_add(),同樣會導致後者函式產生無效結果。
- time.ticks_us() int¶
與上文的
ticks_ms()相同,但以微秒為單位。
- time.ticks_cpu() int¶
與
ticks_ms()和ticks_us()類似,但具有系統中可能達到的最高解析度。這通常是 CPU 時脈,函式因此而命名。但它不一定是 CPU 時脈,也可以改用系統中可用的其他計時來源(例如高解析度計時器)。此函式確切的計時單位(解析度)在time模組層級未加以指定,但特定移植版本的文件可能提供更具體的資訊。此函式適用於非常精細的基準測試或非常緊湊的即時迴圈。請避免在可攜式程式碼中使用它。它在所有 OpenMV Cam 上皆可使用。
- time.ticks_add(ticks: int, delta: int) int¶
將 ticks 值偏移指定的數量,該數量可正可負。給定一個 ticks 值,此函式可依 tick 值的模算術定義(見上文
ticks_ms())計算該值之前或之後 delta 個 tick 的 ticks 值。ticks 參數必須直接是呼叫ticks_ms()、ticks_us()或ticks_cpu()函式的結果(或前一次呼叫ticks_add()的結果)。然而,delta 可以是任意整數或數值運算式。ticks_add()適用於計算事件/任務的期限。(註:你必須使用ticks_diff()函式來處理期限。)範例:
# Find out what ticks value there was 100ms ago print(ticks_add(time.ticks_ms(), -100)) # Calculate deadline for operation and test for it deadline = ticks_add(time.ticks_ms(), 200) while ticks_diff(deadline, time.ticks_ms()) > 0: do_a_little_of_something() # Find out TICKS_MAX used by this port print(ticks_add(0, -1))
- time.ticks_diff(ticks1: int, ticks2: int) int¶
測量從
ticks_ms()、ticks_us()或ticks_cpu()函式回傳的值之間的 ticks 差,以可能回繞的帶號值表示。引數順序與減法運算子相同,
ticks_diff(ticks1, ticks2)的意義與ticks1 - ticks2相同。然而,ticks_ms()等函式回傳的值可能會回繞,因此直接對它們使用減法會產生不正確的結果。這正是為何需要ticks_diff():它實作模算術(更具體地說是環算術),即使對回繞值也能產生正確結果(只要它們彼此相距不太遠,見下文)。此函式回傳 [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] 範圍內的帶號值(這是二補數帶號二進位整數的典型範圍定義)。若結果為負,表示 ticks1 在時間上早於 ticks2 發生。否則表示 ticks1 在 ticks2 之後發生。此關係僅在 ticks1 與 ticks2 彼此相距不超過 TICKS_PERIOD/2-1 個 tick 時成立。若不成立,將回傳不正確的結果。具體而言,若兩個 tick 值相距 TICKS_PERIOD/2-1 個 tick,函式將回傳該值。然而,若它們之間經過了 TICKS_PERIOD/2 個即時 tick,函式將改為回傳 -TICKS_PERIOD/2,亦即結果值會回繞至可能值的負範圍。上述限制的非正式說明:假設你被鎖在一個房間裡,除了一個標準的 12 刻度時鐘外,沒有任何方式監測時間流逝。那麼,若你現在看了一眼錶盤,接著 13 個小時不再看(例如你睡了很久),等你終於再看一次時,你可能會以為只過了 1 個小時。為避免這種錯誤,只要定時看時鐘即可。你的應用程式也應如此。「睡太久」這個比喻也可直接對應到應用程式的行為:不要讓你的應用程式持續執行任何單一任務太久。應分步驟執行任務,並在其間進行計時。
ticks_diff()的設計可因應各種使用模式,其中包括:帶逾時的輪詢。在這種情況下,事件的先後順序已知,你只會處理
ticks_diff()的正值結果:# Wait for GPIO pin to be asserted, but at most 500us start = time.ticks_us() while pin.value() == 0: if time.ticks_diff(time.ticks_us(), start) > 500: raise TimeoutError
排程事件。在這種情況下,若事件已逾期,
ticks_diff()結果可能為負:# This code snippet is not optimized now = time.ticks_ms() scheduled_time = task.scheduled_time() if ticks_diff(scheduled_time, now) > 0: print("Too early, let's nap") sleep_ms(ticks_diff(scheduled_time, now)) task.run() elif ticks_diff(scheduled_time, now) == 0: print("Right at time!") task.run() elif ticks_diff(scheduled_time, now) < 0: print("Oops, running late, tell task to run faster!") task.run(run_faster=true)
註:請勿將
time()值傳給ticks_diff(),你應對它們使用一般的數學運算。但請注意time()也可能(並且將會)溢位。這就是所謂的 https://en.wikipedia.org/wiki/Year_2038_problem 。
- time.time() int¶
回傳自紀元起算的秒數(以整數表示),前提是底層 RTC 已依上文所述設定並維護。若 RTC 未設定,此函式會回傳自移植版本特定參考時間點起算的秒數(對於沒有電池備援 RTC 的嵌入式電路板,通常是自上電或重置起算)。若你想開發可攜式的 MicroPython 應用程式,不應依賴此函式提供高於秒級的精度。若你需要更高精度的絕對時間戳記,請使用
time_ns()。若可接受相對時間,則使用ticks_ms()與ticks_us()函式。若你需要日曆時間,不帶引數的gmtime()或localtime()是更好的選擇。與 CPython 的差異
在 CPython 中,此函式回傳自 Unix 紀元(1970-01-01 00:00 UTC)起算的秒數,以浮點值表示,通常具有微秒精度。在 OpenMV Cam 上,它回傳具有一秒精度的整數 —— 硬體無法在一個浮點數中同時表示長時間範圍與次秒精度 —— 且紀元因電路板而異(見上文的時間紀元)。若沒有已設定的電池備援 RTC,它則改為計算自上電/重置起算的秒數。