time -- 時間関連の関数

このモジュールは、該当する CPython モジュールのサブセットを実装しています。 詳しくはオリジナルの CPython ドキュメンテーションを参照してください: time.

この time モジュールには、現在の日時の取得、時間隔の測定、遅延の機能があります。

エポックタイム: Unix ポートは、1970年1月1日 00:00:00 UTC の POSIX システムエポックの標準を使います。ただし、組込み機器のポートによっては、2000年1月1日 00:00:00 UTC のエポックを使います。エポック年は gmtime(0)[0] で分かります。

実際のカレンダーの日付/時間の維持: これにはリアルタイムクロック(RTC: Real Time Clock)が必要です。基盤 OS (一部の RTOS も含む)を持つシステムでは、RTC が暗黙的に存在することが前提となっています。実際のカレンダー時間の設定と維持は、OS/RTOS の責務であり、MicroPython の外部で行われ、日時/時間を照会するために OS の API を使うだけです。しかし、ベアメタルポートでは、システム時間は machine.RTC() オブジェクトに依存します。現在のカレンダー時間は machine.RTC().datetime(tuple) 関数を使って設定し、以下の手段によって維持されます。

  • バックアップバッテリ(特定のボード用の追加オプションコンポーネントとして用意されていることもあります)。
  • NTP (Networked Time Protocol)を利用(ポート/ユーザーによる設定が必須)。
  • 各電源投入時にユーザが手動で設定(多くのボードはハードリセット時に RTC 時間を設定しますが、再度設定する必要があるボードもあります)。

実際のカレンダー時間が システム/MicroPython RTC で維持されていない場合、現在の絶対時間を参照する必要がある関数は、期待どおりに動作しない可能性があります。

関数

time.gmtime([secs])
time.localtime([secs])

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()

これは localtime の逆関数です。引数は、ローカルタイムの時間を表現する完全な8項目のタプルです。この関数は2000年1月1日以降の秒数を整数で返します。

time.sleep(seconds)

指定された秒数の間スリープします。ボードによっては秒以下の精度でスリープするために、浮動小数点数で秒を指定できるものがあります。他のボードでは、sleep_ms()sleep_us() 関数との整合性のために、浮動小数点の引数を受け付けないことに注意してください。

time.sleep_ms(ms)

指定のミリ秒間遅延します。ミリ秒の指定は0以上の整数である必要があります。

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

time.sleep_us(us)

指定のマイクロ秒間だけ遅延します。マイクロ秒の指定は0以上の整数である必要があります。

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

time.ticks_ms()

呼出し時点での稼働時間をミリ秒単位で返します。稼働時間は最大値に達するとラップアラウンドします(一周して最低値に戻ります)。

ラップアラウンド値は陽に公開されませんが、説明を簡略化するために 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()

上記の ticks_ms() と同様ですが、マイクロ秒単位となります。

time.ticks_cpu()

ticks_ms()ticks_us() に似ていますが、システムの可能な限り高い精度でとなります。これは通常 CPU クロックです。そのため、このような名前が付けられています。しかし、CPU クロックである必要はなく、代わりにシステム内で使用可能な他のタイミングソース(たとえば、高分解能タイマー)を使用することもできます。この機能の正確なタイミング単位(精度)は、 time モジュールレベルでは指定されていませんが、特定のポートのドキュメントによって、より具体的な情報が提供される場合があります。この関数は、非常に細かいベンチマークや非常にタイトなリアルタイムループで使うことを目的としています。ポータブルコードでの使用は避けてください。

可用性: すべてのポートがこの機能を実装しているわけではありません。

time.ticks_add(ticks, delta)

与えた数をティック値からのオフセットとして加算した値を返します。引数の値は正でも負でもかまいません。この関数は、ティック値のモジュール算術定義(上記の ticks_ms() を参照)にしたがい、与えた ticks 値とその前後の delta ティックからティック値を算出します。 ticks パラメータには ticks_ms(), ticks_us(), ticks_cpu() を呼出した直の結果(または ticks_add() を前に呼出したの結果)を与えなければなりません。ただし delta は任意の整数または数値式にすることができます。ticks_add() はイベント/タスクのデッドラインを算出するのに便利です。(注記: デッドラインを扱うには ticks_diff() を使う必要があります。)

サンプルコード:

# 100ms 前のティック値を調べます
print(ticks_add(time.ticks_ms(), -100))

# 操作やテストのためのデッドラインを算出します
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
    do_a_little_of_something()

# このポートの TICKS_MAX を調べます
print(ticks_add(0, -1))
time.ticks_diff(ticks1, ticks2)

ticks_ms(), ticks_us(), ticks_cpu() 関数の戻り値(ラップアラウンドである可能性のある符号付きの値)の間のティック値の差を計算します。

引数の順序は減算演算子と同じで、 ticks_diff(ticks1, ticks2)ticks1 - ticks2 と同じ意味を持ちます。しかし、 ticks_ms() などの関数が返す値はラップアラウンドになるえるので、減算演算子を使うと不正な結果になるかもしれません。そのため ticks_diff() が用意されています。この関数を使えばラップアラウンド値であっても正しい結果を生み出すために合同(より具体的には剰余環)算術を実装しています(2つの値が離れすぎていない限りという条件がつきます: 下記参照)。この関数は [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] の範囲(2の補数の符号付き2進整数の典型的な範囲定義です)の 符号付きの 値を返します。結果が負の場合は ticks1ticks2 より早く発生したことを意味します。さもなければ、 ticks1ticks2 の後に発生したことを意味し ます。これは ticks1ticks2TICKS_PERIOD/2-1 ティック以下で互いに離れている場合にのみ維持されます。それが維持されない場合、不正確な結果が返されます。特に、2つのティック値が TICKS_PERIOD/2-1 ティックだけ離れている場合、その値が関数によって返されます。しかし、リアルタイムティック TICKS_PERIOD/2 になると、関数は代わりに -TICKS_PERIOD/2 を返します。つまり、結果値は可能な値の負の範囲にラップアラウンドします。

上記の制約の形式的でない理論的根拠: 部屋に閉じ込められていて、普通の12時間式の時計以外に時間の経過を調べる手段がないとします。ある時刻をチェックした後、13時間経過するまで再度の時刻チェックをしていなかったとします(たとえば、長い眠りに陥っていたなど)。そこで時刻をチェックすると、1時間しか経過していないように見えるでしょう。この間違いを避けるためには、定期的に時計をチェックする必要があります。アプリケーションでも同じことをする必要があります。「長すぎる睡眠」のメタファーは、アプリケーションの振る舞いに直接あてはまります。アプリケーションが単一のタスクを長時間実行しないようにしてください。ステップ単位にタスクを実行し、ステップの間で時間を計測するようにしてください。

ticks_diff() は、さまざまな使用パターンに対応するように設計されています:

  • タイムアウトのポーリング - この場合、イベントの順序は既知であり、次のように ticks_diff() の正の結果のみを処理します:

    # GPIOピンから入力があるのを待つが、最大でも50usまで
    start = time.ticks_us()
    while pin.value() == 0:
        if time.ticks_diff(time.ticks_us(), start) > 500:
            raise TimeoutError
    
  • イベントのスケジューリング - この場合、イベントが期限切れになると ticks_diff() の結果が負になります:

    # このコードは最適化されていません
    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() の値については、通常の算術演算を使用する必要があります。ただし、 time() もオーバーフローする可能性はあります。これは 2038年問題 として知られています。

time.time()

上記のように基礎となる RTC が設定され、維持されていると仮定して、エポック以降の秒数を整数で返します。RTC が設定されていない場合、この関数はポート固有の参照ポイントからの秒数を返します(バッテリバックアップされた RTC のない組込みボードの場合、通常は電源投入またはリセット以降の値となります)。移植性のある MicroPython アプリケーションを開発したい場合は、この関数を使用して秒より高い精度の値を提供するべきではありません。より高い精度の絶対タイムスタンプが必要な場合は time_ns() を使ってください。相対時間が必要な場合は ticks_ms()ticks_us() を使ってください。カレンダー時刻が必要な場合は、引数を指定しない gmtime()localtime() の方が良いでしょう。

CPython との違い

CPythonでは、この関数は Unix エポック 1970-01-01 00:00 UTC からの秒数を浮動小数点として返します。通常はマイクロ秒の精度を持ちます。MicroPython では Unix ポートだけが同じエポックを使い、浮動小数点精度が許せば秒未満の精度で返します。組込みハードウェアは、通常、長い時間範囲と1秒未満の精度の両方を表現するための浮動小数点精度を持たないため、秒精度で整数値を使用します。一部の組込みハードウェアにはバッテリ駆動の RTC がないため、最後の電源投入から、または他の相対的なハードウェア固有のポイント(リセットなど)からの秒数が返されます。

time.time_ns()

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