time --- 時間関連の関数

time モジュールは、現在の時刻と日付の取得、時間間隔の測定、および遅延のための関数を提供します。

時刻エポック: 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 を、(year, month, mday, hour, minute, second, weekday, yearday) を含む 8 要素のタプルに変換します。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 の逆関数です。引数は localtime と同じ形式で時刻を表す完全な 8 要素タプルです。時刻エポックからの秒数を表す整数を返します。

time.sleep(seconds: float) None

指定された秒数だけスリープします。seconds は浮動小数点数でもよく、その場合は端数秒だけスリープします。より細かい遅延や整数のみの遅延には sleep_ms() および sleep_us() 関数を使用してください。

sleep(0) を含め sleep() を呼び出すと、保留中のコールバック関数が必ず呼び出されます。

time.sleep_ms(ms: int) None

指定されたミリ秒数だけ遅延します。値は正の数または 0 でなければなりません。

この関数は少なくとも指定されたミリ秒数だけ遅延しますが、割り込みハンドラや他のスレッドなど、他の処理が行われる必要がある場合はそれより長くかかることがあります。ms に 0 を渡しても、これらの他の処理は引き続き行われます。より正確な遅延には sleep_us() を使用してください。

sleep_ms(0) を含め sleep_ms() を呼び出すと、保留中のコールバック関数が必ず呼び出されます。

time.sleep_us(us: int) None

指定されたマイクロ秒数だけ遅延します。値は正の数または 0 でなければなりません。

この関数は少なくとも us マイクロ秒の正確な遅延を提供しようとしますが、システムが実行すべきより優先度の高い処理を持っている場合はそれより長くかかることがあります。

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_ms() を参照)に従って、その delta ティック前または後のティック値を計算できます。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_diff(ticks1, ticks2)ticks1 - ticks2 と同じ意味を持ちます。ただし、ticks_ms() などの関数が返す値は折り返す場合があるため、それらに対して減算を直接使用すると正しくない結果になります。そのために ticks_diff() が必要であり、これは剰余(より具体的にはリング)演算を実装して、折り返しの値に対しても正しい結果を生成します(ただし両者があまり離れすぎていない場合に限ります。下記参照)。この関数は [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] の範囲の 符号付き 値を返します(これは 2 の補数による符号付き 2 進整数の典型的な範囲定義です)。結果が負の場合、ticks1ticks2 より時間的に早く発生したことを意味します。それ以外の場合は、ticks1ticks2 より後に発生したことを意味します。これが成り立つのは、ticks1ticks2 が互いに TICKS_PERIOD/2-1 ティック以下しか離れていない場合 のみ です。それが成り立たない場合は、正しくない結果が返されます。具体的には、2 つのティック値が TICKS_PERIOD/2-1 ティック離れている場合、関数はその値を返します。しかし、それらの間に実時間で TICKS_PERIOD/2 ティックが経過していた場合、関数は代わりに -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 では、1 秒精度の 整数 を返します(ハードウェアは、長い時間範囲とサブ秒精度の両方を float で表現できないため)。また、エポックはボードによって異なります(上記の 時刻エポック を参照)。設定済みのバッテリーバックアップ付き RTC がない場合は、代わりに電源投入/リセットからの秒数をカウントします。

time.time_ns() int

time() と似ていますが、エポックからのナノ秒数を整数で返します(通常は大きな整数になるため、ヒープ上に確保されます)。

コンストラクタ

class time.clock

clock オブジェクトを返します。

メソッド

tick() None

経過時間の追跡を開始します。

fps() float

経過時間の追跡を停止し、現在の FPS(1 秒あたりのフレーム数)を返します。

この関数を呼び出す前に、必ず最初に tick を呼び出してください。

avg() float

経過時間の追跡を停止し、現在の平均経過時間をミリ秒単位で返します。

この関数を呼び出す前に、必ず最初に tick を呼び出してください。

reset() None

clock オブジェクトをリセットします。