2021年4月14日掲載、2026年3月10日更新
【datecalc.cのソースコード】
/*
* 日付の間の計算を行うプログラム
* datecalc.c(date calculation)
*
* 1582年10月15日以降(グレゴリオ暦上)、9999年12月31日以前で動作する。
* 西暦0年1月1日((*)拡張したグレゴリオ暦による)からの日数で計算する。
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h> /* strcspn, strcmp, strcat */
#include <ctype.h> /* isdigit */
#define BUF_SIZE 256
/*
* 自作のbool型の定義
*/
typedef enum {
false,
true
} bool;
/*
* 構造体dateの定義
*/
struct date {
int year;
int month;
int day;
};
/*
* ユーザー定義関数の関数原型宣言
*/
void initialize(void);
void menu(char *sel_procp);
void input_enter(void);
void proc1_print_title(void);
bool proc1_input(struct date *d1p, struct date *d2p);
bool input_date(struct date *dp);
bool input_year(int *yearp);
bool is_valid_integer(char buf[]);
bool input_month(int *monthp);
bool input_day(int year, int month, int *dayp);
int get_days_of_the_month(int year, int month);
bool is_leap_year(int year);
int calc_date_diff(struct date d1, struct date d2);
int get_days_to_the_date(struct date d);
int get_days_to_the_year(int year);
int get_days_in_the_year(struct date d);
void proc1_output(struct date d1, struct date d2, int days);
void comma_sep(char *sp, int n);
void output_result_diff(struct date d1, struct date d2, char strdays[]);
void foutput_result_diff(struct date d1, struct date d2, char strdays[]);
void gen_filename(char filename[]);
bool retry(void);
void proc2_print_title(void);
bool proc2_input(struct date *d1p, int *days, char *opp);
struct date calc_addsub(struct date base, int days, char op);
bool is_out_of_range(struct date d);
void proc2_output(struct date d1, struct date d2, int days, char op);
void output_result_addsub(struct date d1, struct date d2,
char strdays[], char addsub);
void foutput_result_addsub(struct date d1, struct date d2,
char strdays[], char addsub);
/*
* グローバル変数
*/
bool is_first_output = true;
char filename[BUF_SIZE];
/*
* メイン関数
*/
int main(void)
{
struct date date1, date2;
int days;
char addsub, sel_proc;
/* 初期化 */
initialize();
while (1) {
do_menu:
/* メニュー */
menu(&sel_proc);
/* メニューからの処理の分岐 */
switch (sel_proc) {
/* 処理1(差の計算) */
case '1':
/* 処理1中の標題の表示 */
proc1_print_title();
/* 処理1中の入力 */
if (!proc1_input(&date1, &date2))
/* qが押されたらメニューへ */
goto do_menu;
/* 処理1中の計算 */
days = calc_date_diff(date1, date2);
/* 処理1中の出力 */
proc1_output(date1, date2, days);
/* 操作を繰り返すかどうかの選択 */
if (!retry())
goto do_end;
break;
/* 処理2(日数の足し算引き算) */
case '2':
/* 処理2中の標題の表示 */
proc2_print_title();
while (1) {
/* 処理2中の入力 */
if (!proc2_input(&date1, &days, &addsub))
/* qが押されたらメニューへ */
goto do_menu;
/* 処理2中の計算 */
date2 = calc_addsub(date1, days, addsub);
/* 計算結果の日付が計算対象の範囲外かどうかで分岐 */
if (!is_out_of_range(date2))
break;
}
/* 処理2中の出力 */
proc2_output(date1, date2, days, addsub);
/* 操作を繰り返すかどうかの選択 */
if (!retry())
goto do_end;
break;
/* 処理0(プログラムの終了) */
case '0':
goto do_end;
}
}
do_end:
printf("\nプログラムを終了します。\n");
return EXIT_SUCCESS;
}
/*
* 初期化を行う関数
*/
void initialize()
{
/* 乱数系列の設定 */
srand((unsigned int)time(NULL));
}
/*
* メニューの関数
* input_enter関数を使用する。
*/
void menu(char *sel_procp)
{
char buf[BUF_SIZE], zz;
/* 標題の表示 */
printf("【日付に関する2通りの計算を行います】\n\n");
input_enter();
printf("次のいずれかを選択してください。\n\n");
/* 処理の選択 */
while (1) {
printf("1.2つの日付の間の差を計算する。\n"
"2.ある日付に日数を足したり引いたりする。\n"
"0.終了する。\n\n0、1、2のどれですか? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", sel_procp, &zz);
if ((*sel_procp != '0' && *sel_procp != '1' && *sel_procp != '2') ||
zz != '\n') {
printf("\n無効な入力です。\n\n");
input_enter();
printf("0、1、2のいずれかを入力してください。\n\n");
continue;
}
break;
}
}
/*
* エンターキーの入力を受け付ける関数
*/
void input_enter(void)
{
char buf[BUF_SIZE], zz;
while (1) {
printf("エンターキーを押してください・・・");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c", &zz);
if (zz != '\n')
continue;
break;
}
printf("\n");
}
/*
* 処理1中の標題を表示する関数
* input_enter関数を使用する。
*/
void proc1_print_title(void)
{
printf("\n【2つの日付の間の差を計算します】\n\n");
input_enter();
printf("「日付1」をより古い日付、「日付2」をより新しい日付とします。\n\n");
input_enter();
}
/*
* 処理1中の入力処理をする関数
* true: 次に進む、false: 中断してメニューに戻る。
* input_date関数およびinput_enter関数を使用する。
*/
bool proc1_input(struct date *d1p, struct date *d2p)
{
while (1) {
printf("まず、日付1を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
if (!input_date(d1p)) {
printf("\n+++++\n\n");
return false;
}
printf("\n次に、日付2を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
if (!input_date(d2p)) {
printf("\n+++++\n\n");
return false;
}
if (10000*d1p->year + 100*d1p->month + d1p->day >
10000*d2p->year + 100*d2p->month + d2p->day) {
printf("日付1と日付2の順序が逆です。\n\n");
input_enter();
printf("日付1がより古い日付、日付2がより新しい日付となるように"
"入力してください。\n\n");
continue;
}
break;
}
return true;
}
/*
* 日付を入力する関数
* true: 次に進む、false: 中断してメニューに戻る。
* input_year関数、input_month関数、input_day関数および
* input_enter関数を使用する。
*/
bool input_date(struct date *dp)
{
while (1) {
/* 年の入力 */
if (!input_year(&dp->year))
return false;
/* 月の入力 */
if (!input_month(&dp->month))
return false;
/* 日の入力 */
if (!input_day(dp->year, dp->month, &dp->day))
return false;
/* 入力結果がグレゴリオ暦の範囲内かどうかで分岐 */
if (10000*dp->year + 100*dp->month + dp->day
< 15821015) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("%d年%d月%d日はグレゴリオ暦の範囲外です。\n"
"本プログラムは、グレゴリオ暦上でしか動作しません。\n"
"1582年10月15日以降の日付を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n",
dp->year, dp->month, dp->day);
continue;
}
break;
}
return true;
}
/*
* 年を入力する関数
* true: 次に進む、false: 中断してメニューに戻る。
* is_valid_integer関数およびinput_enter関数を使用する。
*/
bool input_year(int *yearp)
{
char buf[BUF_SIZE], zz;
while (1) {
printf("年 = ?(西暦で) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", yearp, &zz);
buf[strcspn(buf, "\n")] = '\0';
/* 中断判定 */
if (strcmp(buf, "q") == 0 || strcmp(buf, "Q") == 0)
return false;
if (!is_valid_integer(buf)) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("半角整数値を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
continue;
}
if (*yearp < 0) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("負の値は受け付けません。\n"
"入力をやり直してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
continue;
}
if (*yearp < 1582) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("西暦%d年はグレゴリオ暦の範囲外です。\n"
"1582年以降の年を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n",*yearp);
continue;
}
if (9999 < *yearp) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("本プログラムは9999年までにしか対応していません。\n"
"9999年以前の年を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
continue;
}
break;
}
return true;
}
/*
* 文字列が正しい形式の整数値かどうかを判定する関数
* true: 正しい形式である、false: 無効な形式である。
*/
bool is_valid_integer(char buf[])
{
int i = 0;
/* 空文字列ならば偽を返す */
if (buf[0] == '\0')
return false;
/* 最初は符号(省略可) */
if (buf[i] == '+' || buf[i] == '-')
i++;
/* 次に数字(省略不可) */
if (!isdigit((unsigned char)buf[i]))
return false;
i++;
/* 次に数字列(省略可) */
while (isdigit((unsigned char)buf[i]))
i++;
/* 他に余計な文字がなければ真、あれば偽を返す */
return buf[i] == '\0';
}
/*
* 月を入力する関数
* true: 次に進む、false: 中断してメニューに戻る。
* is_valid_integer関数およびinput_enter関数を使用する。
*/
bool input_month(int *monthp)
{
char buf[BUF_SIZE], zz;
while (1) {
printf("月 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", monthp, &zz);
buf[strcspn(buf, "\n")] = '\0';
/* 中断判定 */
if (strcmp(buf, "q") == 0 || strcmp(buf, "Q") == 0)
return false;
if (!is_valid_integer(buf)) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("半角整数値を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
continue;
}
if (*monthp < 1 || 12 < *monthp) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("月は1から12までです。\n"
"1から12の整数値を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
continue;
}
break;
}
return true;
}
/*
* 日を入力する関数
* true: 次に進む、false: 中断してメニューに戻る。
* get_days_of_the_month関数、is_valid_integer関数および
* input_enter関数を使用する。
*/
bool input_day(int year, int month, int *dayp)
{
char buf[BUF_SIZE], zz;
int days = get_days_of_the_month(year, month);
while (1) {
printf("日 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", dayp, &zz);
buf[strcspn(buf, "\n")] = '\0';
/* 中断判定 */
if (strcmp(buf, "q") == 0 || strcmp(buf, "Q") == 0)
return false;
if (!is_valid_integer(buf)) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("半角整数値を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n");
continue;
}
if (*dayp < 1 || days < *dayp) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("%d年%d月は、1日から%d日までです。\n"
"1から%dの整数値を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n\n",
year, month, days, days);
continue;
}
break;
}
return true;
}
/*
* ある月に含まれる日数を返す関数
* is_leap_year関数を使用する。
*/
int get_days_of_the_month(int year, int month)
{
int days;
switch (month) {
/* 2月 */
case 2:
if (is_leap_year(year))
days = 29;
else
days = 28;
break;
/* 4、6、9、11月 */
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
/* 1、3、5、7、8、10、12月 */
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days = 31;
break;
}
return days;
}
/*
* うるう年の判定をする関数
* true: うるう年である、false: うるう年でない。
*
* 400で割り切れればうるう年である。
* 400で割り切れず、100で割り切れればうるう年でない。
* 100で割り切れず、4で割り切れればうるう年である。
* 4で割り切れなければうるう年でない。
*/
bool is_leap_year(int year)
{
return (year % 400 == 0 || (year % 100 && year % 4 == 0));
}
/*
* 処理1中の計算をする関数
* get_days_to_the_date関数を使用する。
*/
int calc_date_diff(struct date d1, struct date d2)
{
return
get_days_to_the_date(d2) -
get_days_to_the_date(d1);
}
/*
* 西暦0年1月1日(*)からその日までの日数を返す関数
* ((*)拡張したグレゴリオ暦による)
* get_days_to_the_year関数とget_days_in_the_year関数を使用する。
*/
int get_days_to_the_date(struct date d)
{
return
get_days_to_the_year(d.year) +
get_days_in_the_year(d);
}
/*
* 西暦0年1月1日(*)からその年の1月1日までの日数を返す関数
* ((*)拡張したグレゴリオ暦による)
* is_leap_year関数を使用する。
*/
int get_days_to_the_year(int year)
{
int numleap = 0, i;
for (i = 0; i < year; i++)
if (is_leap_year(i))
numleap++;
return (365 * year + numleap);
}
/*
* その年(*)の1月1日からその日までの日数を返す関数
* ((*)拡張したグレゴリオ暦による)
* get_days_of_the_month関数を使用する。
*/
int get_days_in_the_year(struct date d)
{
int i, temp_days = d.day - 1;
for (i = d.month - 1; i > 0; i--)
temp_days += get_days_of_the_month(d.year, i);
return temp_days;
}
/*
* 処理1中の出力処理をする関数
* comma_sep関数、output_result_diff関数、foutput_result_diff関数および
* input_enter関数を使用する。
*/
void proc1_output(struct date d1, struct date d2, int days)
{
char strdays[BUF_SIZE], buf[BUF_SIZE], ch, zz;
/* 日数を3桁ずつコンマで区切った文字列に変換 */
comma_sep(strdays, days);
/* 画面への出力 */
output_result_diff(d1, d2, strdays);
/* ファイルに出力するかどうかの分岐 */
while (1) {
printf("\nファイルに出力しますか?(y/n) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &ch, &zz);
if ((ch == 'y' || ch == 'Y') && zz == '\n') {
foutput_result_diff(d1, d2, strdays);
break;
}
else if ((ch == 'n' || ch == 'N') && zz == '\n')
break;
printf("\n無効な入力です。\n\n");
input_enter();
printf("yまたはnを入力してください。\n\n");
}
}
/*
* 数値を3桁ずつコンマで区切った文字列に変換する関数
*/
void comma_sep(char *sp, int n)
{
char *p = sp, c;
int digit = 0, m = n, len = 0;
/* nの桁数をlenに取得 */
if (m == 0)
len = 1;
while (m > 0) {
m /= 10;
len++;
}
/* nが0の場合は"0"を格納 */
if (n == 0) {
*p++ = '0';
*p-- = '\0';
}
/* n > 0の場合は1の位からコンマで区切って格納 */
else {
while (n > 0) {
*p++ = '0' + (n % 10);
n /= 10;
digit++;
if (digit % 3 == 0 && digit != len)
*p++ = ',';
}
*p-- = '\0';
}
/* 文字列を逆順に並べ替え */
while (sp < p) {
c = *sp;
*sp++ = *p;
*p-- = c;
}
}
/*
* 差の計算の結果を画面に出力する関数
*/
void output_result_diff(struct date d1, struct date d2, char strdays[])
{
printf("%d年%d月%d日と%d年%d月%d日の差は、%s日です。\n",
d1.year, d1.month, d1.day, d2.year, d2.month, d2.day, strdays);
}
/*
* 差の計算の結果をファイルに出力する関数
* gen_filename関数を使用する。
*/
void foutput_result_diff(struct date d1, struct date d2, char strdays[])
{
FILE *fp;
/* 新規ファイル出力か追記かの分岐 */
if (is_first_output) {
/* 初めてのファイル出力のときだけファイル名を生成して新規作成 */
gen_filename(filename);
fp = fopen(filename, "w");
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
is_first_output = false; /* 以降は追記状態になる */
}
else {
/* 2回目以降のファイル出力は追記 */
fp = fopen(filename, "a");
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
}
fprintf(fp, "%d年%d月%d日と%d年%d月%d日の差は、%s日です。\n",
d1.year, d1.month, d1.day, d2.year, d2.month, d2.day, strdays);
fclose(fp);
}
/*
* 現在日付時刻からファイル名を生成する関数
*/
void gen_filename(char filename[])
{
char strnumrand[10];
time_t tt = time(NULL);
struct tm *t = localtime(&tt);
sprintf(filename, "datecalc%04d%02d%02d_%02d%02d%02d_",
1900+(t->tm_year), 1+(t->tm_mon), t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
sprintf(strnumrand, "%04d", rand() % 10000);
strcat(filename, strnumrand);
strcat(filename, ".txt");
}
/*
* 操作を繰り返すかどうかを選択する関数
* true: 繰り返す、false: 終了する。
* input_enter関数を使用する。
*/
bool retry(void)
{
bool flag;
char buf[BUF_SIZE], ch, zz;
while (1) {
printf("\n繰り返しますか?(y/n) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &ch, &zz);
if ((ch == 'y' || ch == 'Y') && zz == '\n') {
printf("\n+++++\n\n");
flag = true;
break;
}
else if ((ch == 'n' || ch == 'N') && zz == '\n') {
flag = false;
break;
}
printf("\n無効な入力です。\n\n");
input_enter();
printf("yまたはnを入力してください。\n");
}
return flag;
}
/*
* 処理2中の標題を表示する関数
*/
void proc2_print_title(void)
{
printf("\n【日付に日数を足したり引いたりします】\n\n");
}
/*
* 処理2中の入力処理をする関数
* true: 次に進む、false: 中断してメニューに戻る。
* input_date関数、input_enter関数およびis_valid_integer関数を使用する。
*/
bool proc2_input(struct date *d1p, int *daysp, char *opp)
{
char buf[BUF_SIZE], zz;
/* 日付の入力 */
printf("日付を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n");
if (!input_date(d1p)) {
printf("\n+++++\n\n");
return false;
}
/* +か-かの入力 */
while (1) {
printf("足し算(+)か引き算(-)かを入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n"
"「+」ですか、「-」ですか? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", opp, &zz);
buf[strcspn(buf, "\n")] = '\0';
/* 中断判定 */
if (strcmp(buf, "q") == 0 || strcmp(buf, "Q") == 0) {
printf("\n+++++\n\n");
return false;
}
if ((*opp != '+' && *opp != '-') || zz != '\n') {
printf("\n無効な入力です。\n\n");
input_enter();
printf("半角の「+」または「-」を入力してください。\n\n");
continue;
}
break;
}
/* 日数の入力 */
while (1) {
printf("日数を入力してください。\n"
"入力を中断したい場合は、qを入力してください。\n"
"日数 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", daysp, &zz);
buf[strcspn(buf, "\n")] = '\0';
/* 中断判定 */
if (strcmp(buf, "q") == 0 || strcmp(buf, "Q") == 0) {
printf("\n+++++\n\n");
return false;
}
if (!is_valid_integer(buf)) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("半角整数値を入力してください。\n\n");
continue;
}
if (*daysp < 0) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("負の日数の入力は受け付けません。\n"
"0以上の整数を入力してください。\n\n");
continue;
}
break;
}
return true;
}
/*
* 日付に日数を足したり引いたりする関数
* get_days_of_the_month関数を使用する。
*/
struct date calc_addsub(struct date base, int days, char op)
{
struct date result = base;
/* 足し算か引き算か */
switch (op) {
/* 足し算の場合 */
case '+':
result.day += days;
while (result.day >
get_days_of_the_month(result.year, result.month)) {
result.day -=
get_days_of_the_month(result.year, result.month);
result.month++;
/* 年をまたぐ場合 */
if (result.month > 12) {
result.year++;
result.month = 1;
}
}
break;
/* 引き算の場合 */
case '-':
result.day -= days;
while (result.day < 1) {
result.month--;
/* 年をまたぐ場合 */
if (result.month < 1) {
result.year--;
result.month = 12;
}
result.day +=
get_days_of_the_month(result.year, result.month);
}
break;
}
return result;
}
/*
* 計算結果の日付が計算対象の範囲外かどうかを判定する関数
* true: 範囲外である、false: 範囲内である。
* input_enter関数を使用する。
*/
bool is_out_of_range(struct date d)
{
bool flag = true;
int dvalue = 10000*d.year + 100*d.month + d.day;
/* グレゴリオ暦の範囲外の場合 */
if (dvalue < 15821015) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("1582年10月15日より古い日付は計算できません。\n"
"(グレゴリオ暦の範囲外です。)\n入力をやり直してください。\n\n");
}
/* 9999年12月31日より新しい日付の場合 */
else if (99991231 < dvalue) {
printf("\n無効な入力です。\n\n");
input_enter();
printf("9999年12月31日より新しい日付は計算できません。\n"
"入力をやり直してください。\n\n");
}
/* 計算対象の範囲内の場合 */
else
flag = false;
return flag;
}
/*
* 処理2中の出力処理をする関数
* comma_sep関数、output_result_addsub関数、foutput_result_addsub関数および
* input_enter関数を使用する。
*/
void proc2_output(struct date d1, struct date d2, int days, char op)
{
char strdays[BUF_SIZE], buf[BUF_SIZE], ch, zz;
/* 日数を3桁ずつコンマで区切った文字列に変換 */
comma_sep(strdays, days);
/* 画面への出力 */
output_result_addsub(d1, d2, strdays, op);
/* ファイルに出力するかどうかの分岐 */
while (1) {
printf("ファイルに出力しますか?(y/n) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &ch, &zz);
if ((ch == 'y' || ch == 'Y') && zz == '\n') {
foutput_result_addsub(d1, d2, strdays, op);
break;
}
if ((ch == 'n' || ch == 'N') && zz == '\n')
break;
printf("\n無効な入力です。\n\n");
input_enter();
printf("yまたはnを入力してください。\n\n");
}
}
/*
* 足し算引き算の結果を画面に出力する関数
*/
void output_result_addsub(struct date d1, struct date d2,
char strdays[], char addsub)
{
switch (addsub) {
case '+':
printf("%d年%d月%d日足す%s日は、",
d1.year, d1.month, d1.day, strdays);
break;
case '-':
printf("%d年%d月%d日引く%s日は、",
d1.year, d1.month, d1.day, strdays);
break;
}
printf("%d年%d月%d日です。\n", d2.year, d2.month, d2.day);
}
/*
* 足し算引き算の結果をファイルに出力する関数
* gen_filename関数を使用する。
*/
void foutput_result_addsub(struct date d1, struct date d2,
char strdays[], char addsub)
{
FILE *fp;
/* 新規ファイル出力か追記かの分岐 */
if (is_first_output) {
/* 初めてのファイル出力のときだけファイル名を生成して新規作成 */
gen_filename(filename);
fp = fopen(filename, "w");
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
is_first_output = false; /* 以降は追記状態になる */
}
else {
/* 2回目以降のファイル出力は追記 */
fp = fopen(filename, "a");
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
}
switch (addsub) {
case '+':
fprintf(fp, "%d年%d月%d日足す%s日は、",
d1.year, d1.month, d1.day, strdays);
break;
case '-':
fprintf(fp, "%d年%d月%d日引く%s日は、",
d1.year, d1.month, d1.day, strdays);
break;
}
fprintf(fp, "%d年%d月%d日です。\n", d2.year, d2.month, d2.day);
fclose(fp);
}
C:\Users\skonishi\Documents>datecalc
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・1
エンターキーを押してください・・・[エンター]キー ←[エンター]キー以外の入力なら入力繰り返し。
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 3
無効な入力です。 ←0、1、2のいずれでもなければ入力繰り返し。
エンターキーを押してください・・・[エンター]キー
0、1、2のいずれかを入力してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 2
【日付に日数を足したり引いたりします】
日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 1
無効な入力です。 ←1581年以前の年は無効。
エンターキーを押してください・・・[エンター]キー
西暦1年はグレゴリオ暦の範囲外です。
1582年以降の年を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) -1
無効な入力です。 ←負の値の入力は無効。
エンターキーを押してください・・・[エンター]キー
負の値は受け付けません。
入力をやり直してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 1582y
無効な入力です。 ←数値以外は無効。
エンターキーを押してください・・・[エンター]キー
半角整数値を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 15820
無効な入力です。 ←10000年以降の年は無効。
エンターキーを押してください・・・[エンター]キー
本プログラムは9999年までにしか対応していません。
9999年以前の年を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 1582
月 = ? 1
日 = ? 1
無効な入力です。 ←日付はグレゴリオ暦の範囲内に限る。
エンターキーを押してください・・・[エンター]キー
1582年1月1日はグレゴリオ暦の範囲外です。
本プログラムは、グレゴリオ暦上でしか動作しません。
1582年10月15日以降の日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 1582
月 = ? 10
日 = ? 15
足し算(+)か引き算(-)かを入力してください。
入力を中断したい場合は、qを入力してください。
「+」ですか、「-」ですか? -
日数を入力してください。
入力を中断したい場合は、qを入力してください。
日数 = ? 1
無効な入力です。 ←計算結果がグレゴリオ暦から外れる場合のエラー処理。
エンターキーを押してください・・・[エンター]キー
1582年10月15日より古い日付は計算できません。
(グレゴリオ暦の範囲外です。)
入力をやり直してください。
日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 1582
月 = ? 10
日 = ? 15
足し算(+)か引き算(-)かを入力してください。
入力を中断したい場合は、qを入力してください。
「+」ですか、「-」ですか? -
日数を入力してください。
入力を中断したい場合は、qを入力してください。
日数 = ? -1
無効な入力です。 ←負の日数が入力された場合のエラー処理。
エンターキーを押してください・・・[エンター]キー
負の日数の入力は受け付けません。
0以上の整数を入力してください。
日数を入力してください。
入力を中断したい場合は、qを入力してください。
日数 = ? 0
1582年10月15日引く0日は、1582年10月15日です。
ファイルに出力しますか?(y/n) yy
無効な入力です。 ←yでもnでもなければ入力繰り返し。
エンターキーを押してください・・・[エンター]キー
yまたはnを入力してください。
ファイルに出力しますか?(y/n) y
繰り返しますか?(y/n) x
無効な入力です。 ←yでもnでもなければ入力繰り返し。
エンターキーを押してください・・・[エンター]キー
yまたはnを入力してください。
繰り返しますか?(y/n) y
+++++
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・[エンター]キー
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 2
【日付に日数を足したり引いたりします】
日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 9999
月 = ? 12
日 = ? 31
足し算(+)か引き算(-)かを入力してください。
入力を中断したい場合は、qを入力してください。
「+」ですか、「-」ですか? +
日数を入力してください。
入力を中断したい場合は、qを入力してください。
日数 = ? 1
無効な入力です。 ←計算結果が9999年12月31日より新しい日付になる場合のエラー処理。
エンターキーを押してください・・・[エンター]キー
9999年12月31日より新しい日付は計算できません。
入力をやり直してください。
日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 9999
月 = ? 12
日 = ? 31
足し算(+)か引き算(-)かを入力してください。
入力を中断したい場合は、qを入力してください。
「+」ですか、「-」ですか? +
日数を入力してください。
入力を中断したい場合は、qを入力してください。
日数 = ? 0
9999年12月31日足す0日は、9999年12月31日です。
ファイルに出力しますか?(y/n) y
繰り返しますか?(y/n) y
+++++
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・[エンター]キー
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 2000
無効な入力です。 ←間違えて日付を入力しようとしてもエラー処理される。
エンターキーを押してください・・・[エンター]キー
0、1、2のいずれかを入力してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 2
【日付に日数を足したり引いたりします】
日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 2000
月 = ? 13
無効な入力です。 ←「13月」はありえない。
エンターキーを押してください・・・[エンター]キー
月は1から12までです。
1から12の整数値を入力してください。
入力を中断したい場合は、qを入力してください。
月 = ? 2
日 = ? 30
無効な入力です。 ←「2000年2月30日」はありえない。
エンターキーを押してください・・・[エンター]キー
2000年2月は、1日から29日までです。
1から29の整数値を入力してください。
入力を中断したい場合は、qを入力してください。
日 = ? q ←qを入力すると入力操作が中断される。
+++++
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・[エンター]キー
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 2
【日付に日数を足したり引いたりします】
日付を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 2021
月 = ? 7
日 = ? 23
足し算(+)か引き算(-)かを入力してください。
入力を中断したい場合は、qを入力してください。
「+」ですか、「-」ですか? -
日数を入力してください。
入力を中断したい場合は、qを入力してください。
日数 = ? 100
2021年7月23日引く100日は、2021年4月14日です。 ←「東京オリンピック開幕の100日前」。
ファイルに出力しますか?(y/n) y
繰り返しますか?(y/n) y
+++++
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・[エンター]キー
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 1
【2つの日付の間の差を計算します】
エンターキーを押してください・・・[エンター]キー
「日付1」をより古い日付、「日付2」をより新しい日付とします。
エンターキーを押してください・・・[エンター]キー
まず、日付1を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 2021
月 = ? 7
日 = ? 23
次に、日付2を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 2021
月 = ? 4
日 = ? 14
日付1と日付2の順序が逆です。 ←古い日付から順番に入力するように促される。
エンターキーを押してください・・・[エンター]キー
日付1がより古い日付、日付2がより新しい日付となるように入力してください。
まず、日付1を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 2021
月 = ? 4
日 = ? 14
次に、日付2を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 2021
月 = ? 7
日 = ? 23
2021年4月14日と2021年7月23日の差は、100日です。 ←日数の足し算引き算と日付の差の計算が同じ結果となっている。
ファイルに出力しますか?(y/n) y
繰り返しますか?(y/n) y
+++++
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・[エンター]キー
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 1
【2つの日付の間の差を計算します】
エンターキーを押してください・・・[エンター]キー
「日付1」をより古い日付、「日付2」をより新しい日付とします。
エンターキーを押してください・・・[エンター]キー
まず、日付1を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 1582
月 = ? 10
日 = ? 15
次に、日付2を入力してください。
入力を中断したい場合は、qを入力してください。
年 = ?(西暦で) 9999
月 = ? 12
日 = ? 31
1582年10月15日と9999年12月31日の差は、3,074,323日です。 ←数値が3桁ずつコンマで区切って出力されている。
ファイルに出力しますか?(y/n) y
繰り返しますか?(y/n) y
+++++
【日付に関する2通りの計算を行います】
エンターキーを押してください・・・[エンター]キー
次のいずれかを選択してください。
1.2つの日付の間の差を計算する。
2.ある日付に日数を足したり引いたりする。
0.終了する。
0、1、2のどれですか? 0
プログラムを終了します。
1582年10月15日引く0日は、1582年10月15日です。
9999年12月31日足す0日は、9999年12月31日です。 ←2行目以降が同じファイルに追記されている。
2021年7月23日引く100日は、2021年4月14日です。
2021年4月14日と2021年7月23日の差は、100日です。
1582年10月15日と9999年12月31日の差は、3,074,323日です。
【datecalcの計算例】
●阪神タイガース・藤浪晋太郎投手、1,450日ぶりに甲子園白星
2017年4月27日~2021年4月16日
●大谷翔平、1,072日ぶり勝利
2018年5月20日~2021年4月26日
●ソフトバンクホークス、巨人に708日ぶり黒星
2019年6月22日~2021年5月30日
●阪神タイガース、2,860日ぶりに敵地で中日・大野雄大に黒星つけた
2013年8月23日~2021年6月22日
●上野由岐子、4,717日ぶりの五輪でのピッチング
2008年8月21日~2021年7月21日
●明仁上皇陛下が歴代最長寿に並ぶ32,031日
明仁上皇:1933年12月23日の前日~2021年9月2日
昭和天皇:1901年4月29日の前日~1989年1月7日
●大阪・関西万博まで1,000日
2022年7月18日~2025年4月13日
●阪神タイガース・才木浩人投手、1,159日ぶり勝利
2019年5月1日~2022年7月3日
●阪神・淡路大震災から10,000日
1995年1月17日~2022年6月4日
●中日ドラゴンズ、2,891日振りに単独首位
2016年5月10日~2024年4月9日
●阪神タイガース・湯浅京己投手、977日ぶりに2イニング目のピッチング
2022年9月21日~2025年5月25日
●LAドジャース・大谷翔平、663日ぶりに「二刀流」復帰
2023年8月24日~2025年6月17日
●LAドジャース・大谷翔平、749日ぶりに勝利
2023年8月9日~2025年8月27日
●嵐、1,768日ぶりに5人そろって生配信
2020年12月31日~2025年11月3日
●嵐、1,948日ぶりに新作ミュージックビデオ公開
2020年11月3日~2026年3月5日
©2017 KONISHI, Shoichiro.