日付と時刻
プログラムによっては日付や時刻を取得する必要がある.コンピュータで日付や時刻を操作する場合は,「エポックの起点」からの経過秒(もしくはミリ秒)をもとに行うことが多いようだ(もちろんlocaleも考慮する).「エポックの起点」はシステムによるが,UNIXではGMT 1970年1月1日0時らしい.epochを辞書で引いてみたら,「ある特徴のある時代」らしい.ネットで調べると,「基準時刻」と訳してあったりする.こちらの方がわかりやすいだろうか.
time関数によってエポックの起点からの経過秒を取得できる.
#include <time.h>
#include <stdio.h>
#include <unistd.h>
/* エポックの起点からの経過秒を表示 */
int main()
{
int i;
time_t current_time;
for(i=0;i<10;i++){
/* time関数は引数に返り値と同じ値を格納する.
ここではヌルポインタを引数にしている*/
current_time=time((time_t *)0);
fprintf(stdout,"Current time is %ld\n",current_time);
sleep(1);
}
exit(0);
}
ある処理の直前と直後にtime関数を呼び出してその差を取れば,その処理に要した秒数を取得できる.しかし,time関数の返り値はtime_t型.移植性を考慮するなら差をとるのではなくてdifftime関数を使用した方がいいらしい(time_t型が実際にはint値でない場合を考慮して,ということだろうか).
#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
time_t pre_time;
time_t post_time;
/* ループ前の時刻 */
pre_time=time((time_t *)0);
for(i=0;i<10;i++){
fprintf(stdout,"%ds\n",i);
sleep(1);
}
/* ループ後の時刻 */
post_time=time((time_t *)0);
/* ループに要した時間を出力 */
/* difftime(time_t a,time_t b)はa-bをdouble型で返す. */
fprintf(stdout,"%gs passed \n",difftime(post_time,pre_time));
exit(0);
}
時刻を秒で表されてもどうだろう,という時がある.そういう時にはgmtime関数を使用してtm構造体をつくる.これはJavaでいうと,time関数がDateオブジェクト.getTime()で,tm構造体はCalendarオブジェクトという感じだろうか.実際,tmはtm->tim_secとかして使用するし,Calendarもget(Calendar.SECOND)として使用する.
tm構造体は少なくても以下のメンバを含む.
ここではtm_...と書いている.私のシステムではこうだったのだ(/usr/include/time.h参照).が,Linuxプログラミング(ISBN-7973-0819-2)ではtim_....と書いてあった.なぜだろうか.
tm構造体は少なくても以下のメンバを含む.
| int | tm_sec | 秒(0〜61)閏秒を考慮 |
| int | tm_min | 分(0〜59) |
| int | tm_hour | 時間(0〜23) |
| int | tm_mday | 日(1〜31) |
| int | tm_mon | 月(0〜11).実際の月とは1ずれている |
| int | tm_year | 年(1900年が起点) |
| int | tm_wday | 曜日(0〜6).0は月曜 |
| int | tm_yday | 1年の中での通算年数(0〜365) |
| int | tm_isdst | 夏時間 |
#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
struct tm *s_time;
time_t the_time;
(void) time(&the_time);
s_time=gmtime(&the_time);
/* tm構造体のs_timeから年月日時分秒をとりだす. */
/* tm_yearは1900年からの経過年なので1900を足す */
printf("%4d年%2d月%2d日 %2d時%2d分%2d秒\n",
1900+s_time->tm_year,s_time->tm_mon,s_time->tm_mday,
s_time->tm_hour,s_time->tm_min,s_time->tm_sec);
exit(0);
}
このプログラムを私のシステムで実行すると,9時間ずれていた.プログラムの出力はGMTの値だからだ.これをロケールにあわせた出力にするにはgmtime関数のかわりにlocaltime関数を使用する.というか関数名が体を表している.
#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
struct tm *s_time;
time_t the_time;
(void) time(&the_time);
/* gmtimeではなくlocaltimeを使う */
s_time=localtime(&the_time);
/* tm構造体のs_timeから年月日時分秒をとりだす. */
/* tm_yearは1900年からの経過年なので1900を足す */
printf("%4d年%2d月%2d日 %2d時%2d分%2d秒\n",
1900+s_time->tm_year,s_time->tm_mon,s_time->tm_mday,
s_time->tm_hour,s_time->tm_min,s_time->tm_sec);
exit(0);
}
逆にtm構造体にデータをいれてそこからtime_t型の値を求めるにはmktime関数を使用する.また,上の例では自分でフォーマットを指定して時刻を表示したが,時刻を既定のフォーマットに整形して表示する関数にasctime関数,ctime関数がある.
#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
time_t the_time;
time_t clone_time;
struct tm *s_time;
(void) time(&the_time);
fprintf(stdout,"%ld\n",the_time);
/* mktimeはローカルタイムで記述されているtm構造体を引数にとるので注意. */
s_time=localtime(&the_time);
clone_time=mktime(s_time);
fprintf(stdout,"%ld\n",clone_time);
/* asctimeやctimeが返す文字列を表示 */
/* ctime関数はasctime(localtime(t))と等価 */
fprintf(stdout,"%s",asctime(s_time));
fprintf(stdout,"%s",ctime(&clone_time));
}
tm構造体の要素を取り出したり,逆に要素に値を代入したりするのはちょっと面倒くさい.そこで,便利な関数としてstrftimeとstrptimeがある.strftimeは引数のtm構造体から指定されたフォーマットに必要な要素をとりだして文字列に格納する.sprintfのtime版のような関数だ.
#include <time.h>
#include <stdio.h>
int main()
{
time_t target_time;
struct tm* target_time_tm;
char* time_string;
int string_length=20;
time_string=(char *)malloc(string_length*sizeof(char));
/* time_tをとってそれからローカルなtm構造体を取得. */
(void)time(&target_time);
target_time_tm=localtime(&target_time);
/* tm構造体からフォーマットで指定した文字列を生成 */
(void)strftime(time_string,string_length,"%Y %m/%d %H:%M:%S",target_time_tm);
/* 生成した文字列を出力 */
fprintf(stdout,"%s \n",time_string);
exit(0);
}
実行すると以下のように出力される.
2002 11/03 02:00:34strptimeは逆に引数の文字列が指定されたフォーマットの順に記述されていると仮定してtm構造体の要素を設定していく.
#include <time.h>
#include <stdio.h>
int main()
{
/* 日付を表す文字列 */
char* source_string="2002 11 3 01 50 30";
struct tm* result_tm;
result_tm=(struct tm*)malloc(sizeof(struct tm));
/* source_stringからtm構造体を設定 */
strptime(source_string,"%Y %m %d %H %M %S",result_tm);
/* tm構造体の値を表示.(これには先程のstrftimeの方が便利) */
fprintf(stdout,"%d %d/%d %d:%d:%d\n",
1900+result_tm->tm_year,result_tm->tm_mon+1,result_tm->tm_mday,
result_tm->tm_hour,result_tm->tm_min,result_tm->tm_sec);
exit(0);
}
なお,strftimeとstrptimeのフォーマットに使用できる変換指定子はmanに書いてある.

