
C言語基礎|日付と時刻の書き込み
「タイムスタンプを保存しましょう!」— fprintf を使用して現在の日付と時刻をファイルに書き込みます。
ファイルから読み取れるようになったら、次は「ファイルへ書く」です。
とくに日付と時刻を書き込めるようになると、ログ作成や実行履歴の記録ができて、プログラムがぐっと実用的になります。
画面に出す printf と同じ感覚で、ファイルにも出力したいですよね。
その役を担当するのが fprintf です。printf は stdout(画面)に出しますが、fprintf は出力先のストリームを選べるので、ファイルに書き込めます。
さらに time と localtime を使えば「今この瞬間」の時刻を取り出して、ファイルへ保存できます。

fprintf は「出力先を指定できる printf」
printf と fprintf の違い
| 関数 | 出力先 | 何が便利? |
|---|---|---|
| printf | stdout(通常は画面) | その場で表示できる |
| fprintf | 任意のストリーム(fp や stderr など) | ファイルやエラー出力に書ける |
表の説明
- fprintf は printf の先頭に「出力先 stream」を追加した形です。
- fp にファイルのストリームを渡せばファイルへ、stderr を渡せばエラー用に出せます。
fprintf の書式(命令の形式)
書式
| 項目 | 内容 |
|---|---|
| ヘッダ | #include <stdio.h> |
| 形式 | int fprintf(FILE *stream, const char *format, ...); |
| 動作 | stream が指す先へ、format で整形した文字列を書き込む |
| 返り値 | 書き込んだ文字数(出力エラー時は負の値) |
表の説明
- 戻り値は「何文字出したか」です。
- 重要なログでは、必要に応じて負の値かどうかを見てエラー処理できます。
「現在時刻」を作る流れ(time と localtime)
日付と時刻は、標準ライブラリの関数呼び出しで取得できます。
図:現在時刻の取得フロー
time(NULL)
↓ 現在の暦時刻(time_t)
localtime(&now)
↓ 年月日・時分秒に分解された struct tm*
tm_year / tm_mon / tm_mday / tm_hour / tm_min / tm_sec
図の説明
- time(NULL) は「今」を time_t で返します。
- localtime はそれを「地方時のカレンダー形式」に分解して struct tm を返します。
- tm_year と tm_mon は表示用の補正が必要です(下の表で整理します)。
struct tm の要素(補正が必要なところがポイント)
よく使うメンバと意味
| メンバ | 意味 | 値の例 | 表示用の補正 |
|---|---|---|---|
| tm_year | 1900年からの年数 | 126(=2026年) | +1900 |
| tm_mon | 月(0が1月) | 1(=2月) | +1 |
| tm_mday | 日 | 15 | なし |
| tm_hour | 時 | 22 | なし |
| tm_min | 分 | 10 | なし |
| tm_sec | 秒 | 3 | なし |
表の説明
- tm_year は「2026」そのものではなく「1900からの差」なので、必ず +1900 します。
- tm_mon は 0 始まり(0=1月)なので、必ず +1 します。
- ここを忘れると「年が1900年台」「月が1つズレる」事故が起きます。
サンプルプログラム
ログファイルに1行でタイムスタンプを書くプログラム例です。
プロジェクト名:chap13-5-1 ソースファイル名:chap13-5-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
Windows の Visual Studio が実行環境の場合、以下のパスに「run_log.txt」が作成されます。
C:\Users\<ユーザー名>\source\repos\chap13-5-1\chap13-5-1
#include <stdio.h>
#include <time.h>
int main(void)
{
/* 実行履歴としてタイムスタンプを追記する */
FILE *fp = fopen("run_log.txt", "a");
if (fp == NULL) {
printf("ERROR: Failed to open run_log.txt.\n");
return 1;
}
/* 現在時刻を取得して、年月日・時分秒に分解する */
time_t now = time(NULL);
struct tm *t = localtime(&now);
/* 読みやすい形式で書き込む(例: 2026-02-15 22:10:03) */
int n = fprintf(fp, "%04d-%02d-%02d %02d:%02d:%02d\n",
t->tm_year + 1900,
t->tm_mon + 1,
t->tm_mday,
t->tm_hour,
t->tm_min,
t->tm_sec);
/* 書き込み失敗を軽くチェックする */
if (n < 0) {
printf("ERROR: Failed to write to the log file.\n");
fclose(fp);
return 1;
}
fclose(fp);
printf("Timestamp saved to run_log.txt.\n");
return 0;
}図で理解:このプログラムがやっていること
図:タイムスタンプを書いて閉じる
fopen(run_log.txt, a)
↓
time(NULL) → localtime(&now)
↓
fprintf(fp, "YYYY-MM-DD HH:MM:SS")
↓
fclose(fp)
↓
printf で完了メッセージ
図の説明
- a(追加)で開くので、実行するたびに run_log.txt の末尾に行が増えます。
- fclose は「残ったバッファを書き出して閉じる」ので、最後の締めとして重要です。
printf と fprintf(stdout, ...) は同じ感覚でOK
標準出力ストリーム stdout は FILE* なので、fprintf の第1引数にそのまま渡せます。
同じ働きになる例
| やりたいこと | 書き方A | 書き方B |
|---|---|---|
| 画面へ整数を出す | printf("%d", x); | fprintf(stdout, "%d", x); |
| キーボードから整数を読む | scanf("%d", &x); | fscanf(stdin, "%d", &x); |
表の説明
- printf は「出力先が stdout 固定の fprintf」と考えると理解が一気に楽になります。
- 同様に scanf は「入力元が stdin 固定の fscanf」です。
よくあるつまずきポイント
ありがちなミスと対策
| ミス | 起きること | 対策 |
|---|---|---|
| fopen の失敗をチェックしない | fp が NULL のまま fprintf して危険 | if (fp == NULL) で分岐 |
| tm_year をそのまま使う | 年が 1900 ずれる | +1900 |
| tm_mon をそのまま使う | 月が 1 ずれる | +1 |
| fclose を忘れる | 書いたはずの内容が残らないことがある | 最後に必ず fclose |
表の説明
- とくに fclose 忘れは「たまに起きる」ので厄介です。習慣で潰すのが一番です。
演習問題
演習13-4:複数人のデータをファイルへ書く
キーボードから複数人分の 名前 身長 体重 を読み込み、people.txt に空白区切りで書き込め。
入力終了は名前に end が入力されたときとする。保存形式は 名前 身長 体重 の順とする。
解答例
プロジェクト名:chap13-5-2 ソースファイル名:chap13-5-2.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
Windows の Visual Studio が実行環境の場合、以下のパスに「people.txt」が作成されます。
C:\Users\<ユーザー名>\source\repos\chap13-5-2\chap13-5-2
#include <stdio.h>
int main(void)
{
/* 人のデータを保存するファイルを作る(既存なら中身は消える) */
FILE *fp = fopen("people.txt", "w");
if (fp == NULL) {
printf("ERROR: Cannot open people.txt.\n");
return 1;
}
char name[100];
double height, weight;
printf("Enter records. Type end to finish.\n");
while (1) {
printf("Name: ");
if (scanf("%99s", name) != 1) {
printf("ERROR: Input failed.\n");
break;
}
/* end なら終了 */
if (name[0]=='e' && name[1]=='n' && name[2]=='d' && name[3]=='\0')
break;
printf("Height Weight: ");
if (scanf("%lf%lf", &height, &weight) != 2) {
printf("ERROR: Invalid numbers.\n");
break;
}
/* ファイルへ書き込む(名前 身長 体重) */
fprintf(fp, "%s %.1f %.1f\n", name, height, weight);
}
fclose(fp);
printf("Saved to people.txt.\n");
return 0;
}解説
- fprintf(fp, ...) を使うことで「画面ではなくファイルへ出力」できます。
- w で開くので、people.txt は毎回まっさらから作り直されます。
- scanf の戻り値チェックで入力の失敗を検出できます。
- end を合図にしてループを止めると、入力回数を自由にできます。
