時間の処理でで大ハマり

Unix/Linux 理論と実践」を参考にしてwhoコマンドのオリジナル版を作っている途中で、time_t型で表現された時刻から年、月、日、時間、分を取り出す必要が出てきました。man ctimeによると次の関数を使うことでやりたい処理が実現できそうでした。

struct tm *gmtime(const time_t *timep);

gmtime関数の引数にtime_t型の変数を入れてやると、年、月、日、時間、分などを格納したtm構造体へのポインタが返されます。ここまで分かれば年、月、日、時間、分を取り出すのは簡単だと思い、次のコードを書いたのですが上手にいきませんでした。

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

int main()
{
  time_t time = 1209524199; /* 2008-04-30 11:56 */

  struct tm *mytm = gmtime(&time);

  printf("%d-%d-%d %d:%d",
	 mytm->tm_year,
	 mytm->tm_mon,
	 mytm->tm_mday,
	 mytm->tm_hour,
	 mytm->tm_min);

  return 0;

}

実行してみると、

108-3-30 2:56

と表示され、2008-04-30 11:56とは表示されませんでした。そこで、/usr/include/time.hを調べてみると

struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/

以下省略

と書いてありました。なるほど、tm_yearに1900を、tm_monに1を足せば良さそうです。

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

int main()
{
  time_t time = 1209524199; /* 2008-04-30 11:56 */

  struct tm *mytm = gmtime(&time);

  printf("%d-%d-%d %d:%d",
	 mytm->tm_year + 1900,
	 mytm->tm_mon + 1,
	 mytm->tm_mday,
	 mytm->tm_hour,
	 mytm->tm_min);

  return 0;

}

実行結果は

2008-4-30 2:56

となり、時間だけがおかしい状態となりました。さらに調べてみると、どうやら時間をローカルな時間(日本時間)に変換しなければいけないことが分かりました.

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

int main()
{
  time_t time = 1209524199; /* 2008-04-30 11:56 を示す */

  struct tm *mytm = localtime(&time);

  printf("%d-%d-%d %d:%d",
	 mytm->tm_year + 1900,
	 mytm->tm_mon + 1,
	 mytm->tm_mday,
	 mytm->tm_hour,
	 mytm->tm_min);

  return 0;

}

これで、2008-4-30 11:56という時刻が正しく表示されるようになりました。後で分かったことですが、この手の話は次のサイト様に書かれていました。

これでCでの時間の扱いに少し詳しくなりました。しかし,ここまでたどり着くまでに結構な時間を使ってしまいました...

参考

  • man ctime
  • /usr/include/time.h