Index

HOME > プログラムTOP > C++



C++の壺・時間処理篇

 C++の基本テクニックのTipsです。コンピュータは独自の方式で時間を管理しています。時間処理篇では、それを元に、日時を表現する方法や、経過時間を計算する方法を扱います。
[INDEX] tm構造体 :: 日時を表現する構造体
日時の表現 :: time関数と日時のフォーマット
経過時間 :: clock関数とsleep

sasaraan programming

Exposition

●tm構造体

 時間を表現する構造体に tm構造体があります。この構造体は次のように定義されています。
// tm 構造体
struct tm
{
    int tm_sec;      // 秒 : 0 ... 59
    int tm_min;      // 分 : 0 ... 59
    int tm_hour;     // 時 : 0 ...23
    int tm_mday;    // 日 : 1 ... 31
    int tm_mon;     // 1月からの月数 : 0 ... 11
    int tm_year;     // 1900年からの年数
    int tm_wday;     // 日曜からの曜日 : 0 ... 6
    int tm_yday;     // 1月1日からの日数 : 0 ... 365
    int tm_isdst;     // 夏時間は正、そうでなければ0、不明は負
};    
 各要素は経過数値で表されます。ただし、日 (tm_mday) は1、年 (tm_year) は1900 からの経過数値となります。また、月は 0 から始まります。実際の数字とは一つずれます(一月は 0、二月は 1 ... 十二月は 11)ので注意が必要です。
 最後の tm_isdst は夏時間(サマータイム)を表します。ただし、日本時間と協定世界時(UTC)では常に 0 となります。
 この構造体を使うと、システム時間を文字列で表すときに簡単に変換できるようになります。

●日時の表現

 日時を取得するには、time関数を使います。time関数を使うと、現在のシステム時間を取得できます。ただし、1970年1月1日0時0分0秒(異なる日時の場合もあります)からの経過秒数で表現されます。
time function
・書式time_t time( time_t *buf )
・機能システム時間の取得
・引数buf...時間の格納場所
・戻り値通常は1970/1/1 00:00:00 からの秒数
・要件time.h のインクルード
 上記中、データ型 time_t は long型です。
 また、time関数の戻り値を日付文字列に変換する場合は、sprintf関数などを利用してフォーマットする必要があります。この時、tm構造体に変換すると簡単に文字列をフォーマットすることができます。
 tm構造体の変換には、現地時間に変換する localtime関数と、協定世界時であるUTCに変換する gmtime関数とがあります。日本時間と協定世界時との時差は9時間ですので、両者の差は常に9時間となります。
localtime / gmtime function
・書式struct tm *localtime( const time_t *timer )
struct tm *gmtime( const time_t *timer )
・機能時間を tm構造体に変換
・引数timer...時間定数へのポインタ
・戻り値tm構造体へのポインタ
・要件time.h のインクルード
 なお、これらの関数では、通常、1970年1月1日 00:00:00 以前の日時に設定されると変換が行われず、代わりに NULLを返します。
#include <stdio.h>     // printf, sprintf使用
#include <conio.h>    // getch使用
#include <time.h>     // tm構造体, time, localtime, gmtime使用

/* 日時を "○年○月○日(○曜日) 00:00:00" にフォーマット 
     引数 : buf...文字列の格納場所、st...参照するtm構造体へのポインタ
     戻り値 : 格納した文字列へのポインタ        */
char *fmttm(char *buf, struct tm *st) 
{
    char *a[7] = {"日", "月", "火", "水", "木", "金", "土",};

    sprintf(buf, "%d年%d月%d日(%s) %02d:%02d:%02d", 
            st->tm_year + 1900,  /* 年は +1900 が必要 */
            st->tm_mon + 1,       /* 月は +1 が必要 */
            st->tm_mday,            /* 日は 1...31 */
            a[st->tm_wday],         /* 週は 0...6 → 配列 *a[7] の文字列に変換 */
            st->tm_hour,            /* 時は 0...23 (0詰めの二桁で表示) */
            st->tm_min,             /* 分は 0...59 (0詰めの二桁で表示) */
            st->tm_sec);            /* 秒は 0...59 (0詰めの二桁で表示) */
    return buf;
}

// main 関数
int main() 
{
    time_t t;
    struct tm *ltm;
    struct tm *gtm;
    char s[50];

    time(&t);                  // 現在のシステム時間の取得
    printf("%d\n", t);        // → 1123008275 (time_t型のままの値)

    ltm = localtime(&t);  // ローカル時間で tm構造体に変換
    fmttm(s, ltm);             // 文字列へ変換
    printf("%s\n", s);        // → "2005年8月3日(水) 03:44:35"

    gtm = gmtime(&t);     // 協定世界時で tm構造体に変換
    fmttm(s, gtm);            // 文字列へ変換
    printf("%s\n", s);        // → "2005年8月2日(火) 18:44:35"

    if (getch()) return 0;
} 	

●経過時間

 clock関数は、プログラム(プロセス)の開始からの経過時間を tick数で表します。データ型である clock_t は 通常は long 型です。一秒間に何回カウントするかは、 CLOCKS_PER_SEC 定数で定義されています。多くのシステムでは 1000 か 1000.0 に設定 (一秒間に1000tick) されているようです。
clock function
・書式clock_t clock( void )
・機能プロセス開始からの経過時間
・引数なし
・戻り値tick数 (失敗時は -1)
・要件time.h のインクルード
 CLOCKS_PER_SEC がどんな値を取ろうと、[ clock() ÷ CLOCKS_PER_SEC ] で、経過秒数を取得できます。
 この clock関数と CLOCKS_PER_SEC を用いた代表的な関数に sleep関数と呼ばれる( "sleep" は慣例的な呼称)ものがあります。これは指定時間待機する機能を持つ関数です。以下はその定義例です。 ( windows.h が使えるシステムであれば、Sleep関数として定義されています。)
#include <time.h>    // clock, CLOCKS_PER_SEC使用

// millisecミリ秒間待機する
void sleep(int millisec)
{
    clock_t tick;                          // 待機を抜ける時の tick数
    tick = (millisec * CLOCKS_PER_SEC) / 1000 + clock();
    while (tick >=  clock()) ;            // 待機終了の tick数に至るまでループ
}

// main関数
int main() 
{
    sleep(800);      // 起動後 800ミリ秒待機して、
    return 0;         // プログラムを終了
}	
 上記中、sleep関数のところで、CLOCKS_PER_SEC 定数の値が 1000 (または 1000.0 : つまり 1 tick / 1 ミリ秒) であれば、
 tick = millisec + clock();
と同じ結果となります。

www.sasaraan.net

(c) morijoh