サイトマップ / 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言語講座−それ自体コンパイルできる教材を使った講座です−