閉じる

【C言語】ctimeでtime_tから見やすい日時へ使い方と注意

プログラム内で現在時刻を手早く表示したい時、ctimeは非常に便利です。

time_tの値を、人間が読めるローカル時刻の文字列に即座に変換してくれます。

本記事では、C言語初心者の方に向けてctimeの基本、最小サンプル、表示のコツ、そして落とし穴と対処法までを丁寧に解説します。

C言語のctimeとは?time_tを日時文字列に変換

ctimeの役割と宣言

ctimeは、time_t型の時刻(UNIX時刻、秒)を読みやすいローカル時刻の文字列へ変換する標準Cライブラリ関数です。

ヘッダは#include <time.h>を使用します。

宣言

C言語
#include <time.h>

char *ctime(const time_t *timer);
  • 引数timertime_tへのポインタです(値そのものではありません)。
  • 返り値は文字列へのポインタで、内部の静的領域を指します。書き換えやfreeはできません。
  • 失敗時はNULLを返します。

出力の書式と例

出力は固定フォーマットで、概ね次の形になります。

書式

Www Mmm dd hh:mm:ss yyyy\n (終端に'\0')

Wed Apr 16 14:23:05 2025\n

以下の表に各フィールドを示します。

フィールド説明
WwwWed曜日の英語3文字表記(例: Sun, Mon, Tue, …)
MmmApr月の英語3文字表記(例: Jan, Feb, Mar, …)
dd16日(2桁。1桁の日は先頭に空白が入ることがあります)
hh:mm:ss14:23:05時:分:秒(24時間表記)
yyyy2025西暦4桁
改行\n末尾に改行が入ります
終端\0NUL終端(表示はされません)

実際の文字列は合計26文字(改行と終端を含む)が一般的です。

利用シーン

手軽さが魅力のため、次のような用途でよく使われます。

ログやデバッグ出力に現在時刻を付けたい、プロトタイプで素早く時刻を確認したい、一時的なメッセージに人が読める形の時刻を表示したい、といったケースに向いています。

ただし、書式を自由にカスタマイズしたい場合はstrftimeの使用を検討してください

ctimeの使い方

time_tの取得

現在のUNIX時刻はtimeで取得します。

ポインタを渡すかNULLを渡す2通りがあります。

例: 代表的な2つの書き方

C言語
#include <time.h>

// 1) 返り値で受ける
time_t now = time(NULL);  // 失敗時は (time_t)-1
// 2) 変数に格納してもらう
time_t now2;
if (time(&now2) == (time_t)-1) {
    // エラー処理
}

どちらの場合も失敗時には(time_t)-1であるかを確認します。

ctimeの呼び出しと返り値

必ず&を付けてtime_tのアドレスを渡す点に注意します。

返り値は静的領域を指すchar *で、NULLなら失敗です。

C言語
time_t now = time(NULL);
char *s = ctime(&now);          // &を付ける
if (s == NULL) {
    // 失敗時の処理
}

最小サンプル

コメントを多めに入れた、もっとも基本的なサンプルです。

C言語
#include <stdio.h>
#include <time.h>

int main(void) {
    // 現在のUNIX時刻(秒)を取得
    time_t now = time(NULL);
    if (now == (time_t)-1) {
        // 取得失敗はまれですが、念のためチェックします
        perror("time failed");
        return 1;
    }

    // time_t を読みやすい文字列へ変換
    char *s = ctime(&now); // &を忘れない
    if (s == NULL) {
        fprintf(stderr, "ctime failed\n");
        return 1;
    }

    // ctimeが返す文字列には既に改行(\n)が含まれます
    // printf("%s\n", s); とすると空行が1つ余分に出るので注意
    printf("%s", s);

    return 0;
}
実行結果
Wed Apr 16 14:23:05 2025

表示のコツ

ctimeの文字列には末尾の改行が含まれるため、printf("%s", s);のように余計な\nを付けないのがコツです。

文中に埋め込みたい場合や、後ろに他の文字を続けたい場合は、改行を取り除いてから使うと体裁が整います(方法は後述します)。

ctimeの注意点と落とし穴

ローカル時刻になる

ctimeは常にローカル時刻に基づく文字列を返します

UTCが必要な場合はgmtimeや別手段を検討します(本記事では詳細説明は割愛します)。

末尾に改行\nが付く

末尾の改行が最もよくある落とし穴です。

二重の改行や、文字列連結時の体裁崩れを招きます。

改行を消す方法

簡潔に消すにはstrcspnstrchrが便利です。

C言語
#include <stdio.h>
#include <string.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    if (now == (time_t)-1) return 1;

    char *s = ctime(&now);
    if (!s) return 1;

    // 改行位置を探して終端に置き換える
    s[strcspn(s, "\n")] = '
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
time_t now = time(NULL);
if (now == (time_t)-1) return 1;
char *s = ctime(&now);
if (!s) return 1;
// 改行位置を探して終端に置き換える
s[strcspn(s, "\n")] = '\0';  // 改行がなければ末尾の '\0' をそのまま上書きするだけ
printf("現在時刻: [%s]\n", s); // 角括弧内に収まる
return 0;
}
'; // 改行がなければ末尾の '
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
time_t now = time(NULL);
if (now == (time_t)-1) return 1;
char *s = ctime(&now);
if (!s) return 1;
// 改行位置を探して終端に置き換える
s[strcspn(s, "\n")] = '\0';  // 改行がなければ末尾の '\0' をそのまま上書きするだけ
printf("現在時刻: [%s]\n", s); // 角括弧内に収まる
return 0;
}
' をそのまま上書きするだけ printf("現在時刻: [%s]\n", s); // 角括弧内に収まる return 0; }
実行結果
現在時刻: [Wed Apr 16 14:23:05 2025]

返す文字列は静的領域で書き換え不可

ctimeの返す文字列は静的領域で、書き換えたりfreeしたりしてはいけません

必要に応じて自前のバッファへコピーしてから加工します。

正しいコピー例

C言語
#include <stdio.h>
#include <string.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    char *s = ctime(&now);
    if (!s) return 1;

    char buf[26];                        // ctimeの出力は通常26バイト(終端込み)
    // 安全にコピー(超過時は切り詰め)
    snprintf(buf, sizeof(buf), "%s", s);

    // bufは自分の配列なので書き換え可能
    buf[strcspn(buf, "\n")] = '
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
time_t now = time(NULL);
char *s = ctime(&now);
if (!s) return 1;
char buf[26];                        // ctimeの出力は通常26バイト(終端込み)
// 安全にコピー(超過時は切り詰め)
snprintf(buf, sizeof(buf), "%s", s);
// bufは自分の配列なので書き換え可能
buf[strcspn(buf, "\n")] = '\0';      // 改行を落とす
printf("コピー後: %s\n", buf);
return 0;
}
'; // 改行を落とす printf("コピー後: %s\n", buf); return 0; }

複数回の呼び出しで結果が上書きされる

ctimeは毎回同じ静的バッファを使うため、二度目以降の呼び出しで前の結果が上書きされます

次の例で問題を体感できます。

C言語
#include <stdio.h>
#include <time.h>

int main(void) {
    time_t t1 = time(NULL);
    time_t t2 = t1 + 86400; // 1日後と仮定

    char *s1 = ctime(&t1);
    char *s2 = ctime(&t2); // ここで静的バッファが上書き

    // s1もs2も同じ内容(最後に呼んだほうの文字列)が表示される可能性
    printf("s1: %s", s1);
    printf("s2: %s", s2);

    return 0;
}

対策は自前の配列にすぐコピーして保持することです。

C言語
#include <stdio.h>
#include <string.h>
#include <time.h>

int main(void) {
    time_t t1 = time(NULL);
    time_t t2 = t1 + 86400;

    char b1[26], b2[26];

    snprintf(b1, sizeof(b1), "%s", ctime(&t1)); // ただちにコピー
    snprintf(b2, sizeof(b2), "%s", ctime(&t2)); // ただちにコピー

    printf("b1: %s", b1);
    printf("b2: %s", b2);
    return 0;
}

スレッド非対応

ctimeはスレッドセーフではありません

複数スレッドから同時に呼ぶと結果が干渉します。

標準Cだけではスレッド安全な代替は提供されていません

実務では以下を検討します。

  • POSIX環境: ctime_r(非標準)やlocaltime_rstrftime
  • Windows/MSVC: ctime_sなど(実装依存)
  • どうしてもctimeを使うなら、排他制御で呼び出しを直列化

失敗時はNULLをチェック

ctimeは失敗時にNULLを返します

またtimeも失敗時は(time_t)-1です。

どちらもチェックしておくと堅牢です。

C言語
#include <stdio.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    if (now == (time_t)-1) {
        perror("time failed");
        return 1;
    }

    char *s = ctime(&now);
    if (s == NULL) {
        fprintf(stderr, "ctime failed\n");
        return 1;
    }

    printf("%s", s);
    return 0;
}

タイムゾーン(TZ)の影響

ctimeの結果はローカルタイムゾーンの設定に依存します。

多くの環境では環境変数TZの影響を受けますが、設定方法や反映の仕組みは実装依存です。

POSIXではsetenv("TZ", ...)tzset()、Windowsでは_putenv_tzsetなどが使われます。

移植性が重要なら、タイムゾーンに敏感な表示をctimeに任せない設計(例えばUTCで扱い、必要に応じてstrftimeで明示的に整形)が安全です。

よくある間違いと対処

&を付け忘れる

誤り例

ctime(now); 正: ctime(&now); ctimetime_t *を受け取ります。

<time.h>のインクルード忘れ

#include <time.h>を忘れると宣言が見つからず未定義動作を招く可能性があります。

必ずヘッダをインクルードしてください。

改行を消さずに文字列連結して体裁が崩れる

誤り例

printf("Now: %s - end\n", ctime(&now)); 途中の\nで折り返してしまいます。

対処はstrcspnstrchrで改行を削除してから連結します。

C言語
char *s = ctime(&now);
s[strcspn(s, "\n")] = '
char *s = ctime(&now);
s[strcspn(s, "\n")] = '\0';
printf("Now: %s - end\n", s);
'; printf("Now: %s - end\n", s);

返された文字列をfreeしてしまう誤り

返り値は静的領域なのでfree(s)してはいけません

必要なら自前の配列へコピーします。

返された文字列を書き換えてしまう誤り

直接s[0] = '\0';のように書き換えるのは未定義動作です。

コピーしてから編集してください。

まとめ

ctimeはtime_tからローカル時刻の読みやすい文字列を一瞬で得られる、手軽で強力な関数です。

一方で、末尾の改行が付く静的領域で書き換え不可複数回や並行呼び出しで上書きされるスレッド非対応タイムゾーンの影響を受けるといった注意点があります。

初心者の方は、次の3点をまず押さえると安全です。

  1. アドレスを渡す(&now)
  2. 改行を必要に応じて落とす
  3. 必要なら自前バッファへコピーして保持する

用途が広がってきたら、strftimeなどでの書式指定も学ぶと実務の幅が一気に広がります。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!