時間情報の取得方法と扱い方

作成:

ここではC言語での時間情報の取得方法について説明していく、 時間情報には様々な種類があり、また環境により利用できる関数も変わってくる。 C言語の環境であればどこでも利用できる標準関数から始まり、POSIX環境、Windows環境で利用できるAPIも紹介する。

C言語標準

引き続きC言語の標準関数で、C言語が使える環境であればどこでも使用できる方法を紹介する。 今回紹介するのはC言語標準ではあるが C11(ISO/IEC 9899:2011) という新しい標準で追加されたもののため、 使用できる環境はある程度限られる点に注意していほしい。

timespec_get()

C言語標準関数では、time()は秒単位の時刻しか取れないし、 clock()は実時間ではない。 ということで、これまではC言語標準の関数では秒以下の実時間情報を取得する方法がなかった。 しかし、C11(ISO/IEC 9899:2011) において、以下の関数と構造体が time.h に追加されている。

#include <time.h>
struct timespec {
  time_t tv_sec; /* Seconds.  */
  long tv_nsec;  /* Nanoseconds.  */
};
int timespec_get (struct timespec *ts, int base)

struct timespecはもともと POSIX で定義されていた構造体だ。 tv_secは秒単位の値を格納する。 tv_nsecはナノ秒、1,000,000,000 分の 1 秒単位の値で、 0~999,999,999 の範囲で 1 秒未満の時間を格納する。

この関数から得られる値はこの構造体で UNIX 時間を表現した値となる。 つまり、tv_secの値についてはtime()で取得した値と同じで、 秒未満の値がtv_nsecに格納される。 もちろん、ナノ秒単位の精度で時間情報を扱えるシステムばかりではないだろう。 これは、あくまでその精度まで表現できる構造体ということである。 tv_nsecは、本校執筆現在、 64bit 符号付き整数になっているようである。

現在ではまだ、C11が利用できる環境は限られているが (詳細な確認はできていないが、GCC5.0以降、Visual Studio 2015、などで利用できるようだ) 従来のようにOS依存のAPIを使用しなくて良いため、今後は移植性が高い方法として広まる可能性がある。

使用方法は以下。 baseに指定する値はTIME_UTCしか定義されていない。

#include <stdio.h>
#include <time.h>

int main(int argc, char **argv) {
  struct timespec ts;
  timespec_get(&ts, TIME_UTC);
  printf("%ld %09ld\n", ts.tv_sec, ts.tv_nsec);
  timespec_get(&ts, TIME_UTC);
  printf("%ld %09ld\n", ts.tv_sec, ts.tv_nsec);
  return 0;
}

実行すると以下のようになる。

1446555909 138037037
1446555909 138078350

実行環境によってはもっと分解能の低い値しか取れないかもしれないが、 私の実行環境では printf()による出力にかかる僅かな時間も計測できている。

また、tv_secについてはtime()関数で取得できるのと同じ値なので、 同じ日付等への変換関数を使うことができる。

先にも書いたとおりtimespec_getが使用できる環境は限られている。 (現に私のCygwin環境では利用できない。) そのため、現時点では不用意に使うと、逆に移植性の低いコードになってしまうだろう。 しかし、今後は広く利用できるようになると予想されるので、使用場所を見極めて使うようにしよう。

この情報も時刻情報であるため、システム時計の変更の影響を受ける。