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