サイトマップ / C言語講座出入り口総目次目次:時刻と時間>現在の年月日と時刻

青い直線

現在の年月日と時刻

青い直線

[コンピュータの時計]←このソース→[現在時刻と年月日と曜日を表示]

/* 今日は、typedef 文と、時間に関する関数について学びます。ヘッダーファイル time.h を開くと、下記の記述があります。

    typedef long time_t;

重要:コンパイラによっては、下記のように記述されています。

    typedef unsigned long time_t;

time_t 型のデータがうまく表示されなかったら、time.h を見て下さい。型に合った書式指定子に変えれば、問題は解決します。

typedef は、新しい名前のデータ型を定義します。標準ライブラリ関数 time( ) は、time_t 型をこのように使っています。

    #include <time.h>
    time_t time(time_t *timer);

この関数を呼び出すには、time.h を、インクルードして、timer は time_t 型のポインタなので、

    now = time(&timer);

と記述します。now と timer には、グリニッジ標準時で、1970年1月1日0時0分0秒からの経過時間を、秒単位で表したものが入ります。 */

/* ソースプログラムの説明 */

/* 今回は、time( ) で取得した経過時間から、現在の年月日、および、時刻を割り出します。原理について、簡単に説明します。

例えば、経過時間が、945744117 秒だとしたら、それを、60で割った余りが現在時刻の秒になります。

945744117 秒から現在時刻の秒を引き、その余りを、更に60で割った余りが現在時刻の分になります。

そういう操作を順次繰り返して、時刻を取り出すと、残りは 1970年1月1日からの経過日数になります。

経過日数から閏年でないなら 365 を引き、閏年なら 366 を引いてゆき、残りが1年の日数以下になった所で、西暦年が求められます。

次に、各月の日数を引いてゆき、その月の日数以下になれば、何月か求まり、残りが日付になります。かなり面倒ですが、以上の手順で、年月日と時刻を割り出すことができます。

ソースプログラム中の int 型の IsLeapYear( ) は、西暦年を引数に取り、引数にした年が閏年 ( Leap year ) なら TRUE ( 1 ) を、そうでなければ FALSE ( 0 ) を返します。IsLeapYear( ) の中身の主要な部分は下記の1行です。% 演算子は、整数を整数で割った時の余りを求めるのに使います。

    if (!(year % 4) && ((year % 100) || !(year % 400)))

上記の表現は、少しわかりづらいかも知れません。下記の式が0以外の値をとるのは、

    !(year % 4):4 で割り切れる
    (year % 100):100 で割り切れない
    !(year % 400):400 で割り切れる

4 で割り切れ、かつ、100 で割り切れないか、400 で割り切れれば、 if 文は真になり、閏年です。別の案として、少し長くなりますが、下記のコードも可能です。

    int IsLeapYear2(int year)
    {
        if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))
            return (TRUE);
        else
            return (FALSE);
    }

あるいは、

    int IsLeapYear3(int year)
    {
        if (year % 4)
            return (FALSE);
        else if (!( year % 4) && !(year % 400))
            return (TRUE); 
        else if (!(year % 4) && (year % 100))
            return (TRUE);
    }

このように分けて書くと、可読性は向上します。 */

/* ここからソースプログラム */

#include <stdio.h>
#include <time.h>    /* time(  ) に必要 */

#define TRUE 1
#define FALSE 0

const unsigned long dayofm[ ] = {    /* 閏年でない年の各月の日数 */
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

const unsigned long dayoflm[ ] = {    /* 閏年の各月の日数 */
    31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

const char *monthstr[ ] = {    /* 各月の名前 */
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Des"
};

int IsLeapYear(int year);
void main(void);	

  /* 閏年なら TRUE を返す */
int IsLeapYear(int year)
{
    if (!(year % 4) && ((year % 100) || !(year % 400)))
        return (TRUE);
    else
        return (FALSE);
}

void main(void)
{
    time_t  timer, work, sec, min, hour, day;	
    int month = 1;
    int year = 1970;

    work = time(&timer);    /* 経過時間の取り出し */

    sec = work % 60;        /* 秒を割り出す */
    work -= sec;            /* 秒を引く */
    work = work / 60;       /* 分の単位に変換 */

    min = work % 60;        /* 分を割り出す */
    work -= min;            /* 分を引く */
    work = work / 60;       /* 時の単位に変換 */

    hour = work % 24;       /* 時を割り出す */
    work -= hour;           /* 時を引く */

    day = work / 24;        /* 1970 年からの経過日数を割り出す */

      /* このループを抜けると day には今年の経過日数が残る */
    while (day > 366) {            /* 1970 年から何年経過したか調べる */
        if (IsLeapYear(year))      /* 閏年なら */
            day -= 366;	           /* 366 を引き */
        else                       /* 閏年でなければ */
            day -= 365;            /* 365 を引き */
        year++;                    /* 西暦を 1 増やす */
    }

    day++;                         /* 1 月 1 日は 0 だから */

  /* day には最初は今年の経過日数が入っている。各月の日数を順次引くことにより */
  /* このループを抜けると day にはその月の経過日数 ( 日付 ) が残る */
    while (1) {					
        if (IsLeapYear(year)) {                /* もし閏年なら */
            if (day <= dayoflm[month -1])       /* 月の日数より day が少なければ(等号が抜けていました。(HN)James Bond さんご指摘ありがとうございました。) */
                break;
            else {                             /* 月の日数より day が多ければ */
                day -= dayoflm[month -1];      /* 月の日数を引き */
                month++;                       /* 月を 1 増やす */
            }
        }
        if (!IsLeapYear(year)) {               /* もし閏年でなければ */
            if (day <= dayofm[month -1])        /* 以下同上 */
                break;
            else {
                day -= dayofm[month -1];
                month++;
            }
        }
    }
    printf(" %10ld sec from Jan 1, 1970 00:00:00 \n", timer);        /* 1900になってました。ZEROさんご指摘ありがとうございました。 */
    printf("%s %2ld, %4d \n", monthstr[month - 1], day, year);
    printf("%2ld:%2ld:%2ld\n", hour, min, sec);
}

/* ここまでソースプログラム */

/* メインルーチンにだらだらとコードを書いてしまいました。幾つかの関数に分けることも可能ですが、独立した関数にはならないので、このようにしました。

time_t が long 型で、グリニッジ標準時1970年1月1日0時0分0秒からの経過時間を秒単位で返す処理系の場合、2038年1月19日3時14分7秒にlong 型で表せる最大値を超えます。これを2038年問題といいます。 */

[コンピュータの時計]←このソース→[現在時刻と年月日と曜日を表示]

青い直線

/* (C) 2000- YFプロ. All Rights Reserved. */    提供:C言語講座−それ自体コンパイルできる教材を使った講座です−

青い直線

サイトマップ / C言語講座出入り口総目次目次:時刻と時間>現在の年月日と時刻