時間・時刻処理について(4)

このエントリーをはてなブックマークに追加

今回は、time_t型の時間を文字列に変換する関数と時間差を計算する関数を解説します。

時間を文字列に変換

今回解説する関数は3つです。内2つはUTC/ローカルタイムを考慮した型の変換を行う関数です。
ちなみに、逆方向の型変換を行う関数はmktime(3)で既に紹介済みです。
そして、最後に当然必要になってくる時間差分を求める関数です。

関数名説明
gmtime(3)time_t型をstruct tm型(UTC)へ変換します
localtime(3)time_t型をstruct tm型(ローカルタイム)へ変換します
difftime(3)2つのtime_t型の時間差を求めます


gmtime(3)

time_t型は不便な型ですので文字列で表示する為にctime(3)asctime(3)で文字列に変換を行う方法を紹介しました。
しかし、これらの関数で変換するフォーマットは使いにくいために、フォーマットを指定できるstrftime(3)も紹介しました。
問題はstrftime(3)は引数がstruct tm型だという点にあります。通常時間はtime(2)で時間を作成しますのでtime_t型からの変換が必要になってきます。gmtime(3)はこの変換を行う関数です。


//gmtime.c
#include <stdio.h>
#include <time.h>
int main(void)
{
	time_t t;
	struct tm *m;
	char s[256];

	t = time(NULL);
	m = gmtime(&t);

	strftime(s, sizeof(s), "%Y/%m/%d %H:%M:%S", m);
	printf("%s\n", s);

	return 0;
}

簡単なプログラムですが、変換された値はUTCということと、ctime(3)、asctime(3)と同様に戻り値はgmtime(3)関数の静的なポインタを返すので注意が必要です。

$ gcc -o gmtime gmtime.c
$ ./gmtime
2002/01/01 00:00:00

localtime(3)

gmtime(3)がUTCに変換するのに対して、localtime(3)はローカルタイムに変換します。ローカルタイムの指定をtzname、timezone、daylightという3つのグローバル変数で行います。
この部分をmanから引用します。

関数  localtime()  は、ユーザが指定したタイムゾーンでの時刻要素へ変換する。
この関数は  tzset(3)  を呼び出したかのように振舞い、
大域変数  tzname  に現在のタイムゾーンの情報を設定する。

ややこしいので、ここでは詳しく説明しませんがこれらの変数はtzset(3)によって呼び出されます。
また、tzset(3)は時間関係の各関数で暗黙的に呼ばれますので、通常はこれらの変数を触る必要はありません。知識として頭の片隅にでも置いておいてください。
ではソースコードを見ていきます。

//localtime.c
#include <stdio.h>
#include <time.h>
int main(void)
{
	time_t t;
	struct tm *m;
	char s[256];

	t = time(NULL);

	m = localtime(&t);
	strftime(s, sizeof(s), "%Y/%m/%d %H:%M:%S", m);
	printf("%s\n", s);

	return 0;
}

gmtime(3)とほとんど同じです。注意事項も当然gmtime(3)と同じになります。また、tzname等のグローバル変数へのアクセスを行う場合には十分注意してください。

$ gcc -o localtime localtime.c
$ ./localtime
2002/01/01 09:00:00

difftime(3)

最後は時間差を求める関数です。time_tはUnix上では通常は単なる整数型ですので単なる四則演算で構わないと思います。
しかし、言語仕様上ではどのように定義を行うかは決められていません。そのためにdifftime(3)という関数がわざわざあります。
安全の為にも時間差を求めるときにはdifftime(3)を使用するようにしてください。

//difftime.c
#include <stdio.h>
#include <time.h>
int main(void)
{
	time_t t0;
	time_t t1;
	double diff;

	t0 = time(NULL);

	//何か処理

	t1 = time(NULL);

	diff = difftime(t1, t0);

	printf("%f\n", diff);

	return 0;
}

簡単なプログラムですが、気になるのはclock(3)との違いです。
違いはいくつかありますが、一言でいうとclock(3)は実装に依存する可能性があります。
例えば、clock(3)は正確には"プログラム自身が費した総CPU 時間"です。例えば、マルチプロセス等のプログラムの場合自分以外のプロセスが使用した時間も含まれます。time(3)にはそのような問題はありません。
他にもOS(カーネル)との兼ね合い等も絡んできます。汎用性を考えるのであれば、time(2)とdifftime(3)の併用が望ましいです。

$ gcc -o difftime difftime.c
$ ./difftime
0.130000

まとめ

時間関係の処理は標準関数であってもWeb上では解説が少ないので解説をしましたが、いかがだったでしょうか?
3回に渡って標準関数で提供されている時間関係の関数はこれで終了となります。
次回からはUnixで使える時間関係のシステム関数の解説となります。