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

作成:

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

POSIX環境

ここからは、Linux をはじめとする POSIX 環境で使用できる方法を紹介する。 C言語標準ではないので、使用できる環境は幾分狭まるが、Windowsを除けばほとんどの環境で利用できる。

gettimeofday()

POSIX環境では以下の関数が使用できる。

#include <sys/time.h>
struct timeval {
    time_t tv_sec;            /* Seconds.  */
    suseconds_t tv_usec;      /* Microseconds.  */
};
int gettimeofday(struct timeval *tv, struct timezone *tz);

struct timevalは、 timespec_get()で紹介した struct timespecと非常によく似ている。 tv_secは秒単位の値を格納する。 tv_usecはマイクロ秒、1,000,000 分の 1 秒単位の値で、 0~999,999 の範囲で 1 秒未満の時間を格納する。

この2つの構造体は現在の時刻以外に任意の時間の表現にも使用され、 以下の様な変換マクロも用意されている。値の関係が一目瞭然だろう。

# define TIMEVAL_TO_TIMESPEC(tv, ts) {                                  \
        (ts)->tv_sec = (tv)->tv_sec;                                    \
        (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
}
# define TIMESPEC_TO_TIMEVAL(tv, ts) {                                  \
        (tv)->tv_sec = (ts)->tv_sec;                                    \
        (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
}

gettimeofday()で得られる値は、この構造体で UNIX 時間を表現した値となる。 つまり、tv_secの値についてはtime()で取得した値と同じで、 秒未満の値がtv_usecに格納される。

こちらもどれだけの分解能が得られるかは環境依存となるが、 ソフトウェア制御としては十分な精度で時間を取得できる。

第二引数のstruct timezone *tzは、 名前の通りタイムゾーンの情報を格納するために使用されるのだが、 現在は廃止予定となっており、 POSIX規格では NULL 以外の値を指定した場合の挙動は「未定義」になっている。 そのため、利用する際は必ず NULL を指定する。

使用例は以下

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

int main(int argc, char **argv) {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  printf("%ld %06lu\n", tv.tv_sec, tv.tv_usec);
  gettimeofday(&tv, NULL);
  printf("%ld %06lu\n", tv.tv_sec, tv.tv_usec);
  return 0;
}

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

1446720502 328669
1446720502 328759

……と、ここまで紹介しておいて今更ではあるが、 現在はgettimeofday()という関数自体が非推奨となっており、 今後は次に紹介するclock_gettime()を使用すべきとなっている。

だが、おそらく既存のコードの多くで、もしくは現在開発中のものであっても、まだまだ利用されている関数である。 使用にあたっては臨機応変に対応し、選択可能であれば次項で説明するclock_gettime()を利用するようにしよう。