時刻と時刻の差を「秒」で知りたい場面は、処理時間の測定やタイムアウト判定など、実務でも学習でもたびたび登場します。
C言語には時刻差を安全かつ移植性高く計算できるdifftime関数が用意されています。
本記事ではdifftimeの基礎から具体例、注意点までを初心者向けに丁寧に解説します。
C言語のdifftimeとは?
時刻差(秒)を計算する標準関数
difftimeは2つのtime_t値の差を秒単位で返す、C標準ライブラリの関数です。
標準に含まれるため、OSやコンパイラが異なっても同じインターフェースで利用できます。
内部では実装依存のtime_tを安全に扱い、符号やビット幅の違いによる問題を避けるよう設計されています。
役割の概要
「終点の時刻 − 始点の時刻」を秒で返します。
秒数は実数のdoubleで表され、通常は整数秒になりますが、環境によっては小数部を持ち得ます。
演算はdifftime(end, start)のように、終点を第1引数、始点を第2引数に渡します。
いつ使うか
処理の経過時間を測る、2つのログ時刻の差を比較する、一定時間経過を待つといった用途で使います。
「秒」で比較できればよい場面に最適です。
戻り値はdouble型
戻り値はdouble型です。
これは、非常に大きい時刻差を扱えるようにするためと、実装によってはtime_tが非整数を表す可能性を考慮したためです。
なぜ整数ではないのか
整数にすると表現できる範囲が狭まり、また中間計算でのオーバーフロー検出が難しくなります。
doubleなら広い範囲を扱え、丸め処理も柔軟に行えます。
丸めと表示の考え方
表示の際はprintf("%.0f", diff)のように小数部を抑えて出力したり、必要に応じて%.3fで小数点以下を表示します。
整数秒として使うなら、丸めや切り捨ての方針をあらかじめ決めておきましょう。
必要なヘッダーは<time.h>
#include <time.h>が必須です。
また、結果を表示するにはprintfを使うため#include <stdio.h>も併用します。
インクルード例
#include <stdio.h> // printfなどの入出力
#include <time.h> // time_t, time, difftime
difftimeの基本的な使い方
関数プロトタイプと引数
difftimeのプロトタイプは次の通りです。
// time.h より
double difftime(time_t time1, time_t time0);
// 戻り値: time1 - time0 を秒で表した double
引数の順序に注意
第1引数が「後の時刻」(終点)、第2引数が「前の時刻」(始点)です。
順序を逆にすると負の値が返ります。
2つのtime_tを渡して秒差を得る
典型的にはtime(NULL)で現在時刻を取り、処理の前後で2回取得してdifftimeに渡します。
差が秒単位で得られるため、単純な経過時間計測に適しています。
例の流れ
1回目のtimeで始点を取得し、処理を行い、2回目のtimeで終点を取得します。
この2つをdifftime(end, start)に渡せば秒差が求まります。
結果の表示
表示はprintfで行います。
必要に応じて小数点以下の桁数を調整します。
フォーマット指定の実例
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t0 = time(NULL);
time_t t1 = t0 + 123; // 123秒後の時刻を仮想的に用意
double diff = difftime(t1, t0); // 秒差は123.0になる想定
// 小数なしで表示(四捨五入)
printf("四捨五入: %.0f 秒\n", diff);
// 小数点以下3桁まで表示
printf("小数あり: %.3f 秒\n", diff);
// 切り捨てて整数秒として扱う(明示的にキャスト)
printf("切り捨て: %lld 秒\n", (long long)diff);
return 0;
}
四捨五入: 123 秒
小数あり: 123.000 秒
切り捨て: 123 秒
丸め方は仕様や要件に合わせて統一しましょう。
切り捨てはキャスト、四捨五入は%.0fやllround(要math.h)などの手段があります。
difftimeの実例コード
2つのtime_tの秒差を表示
まずは2つのtime_tの差をそのまま表示する最小例です。
ここでは現在時刻に90秒を足して、90秒差が出ることを確認します。
#include <stdio.h>
#include <time.h>
int main(void) {
// 現在のUNIX時刻(秒)を取得
time_t start = time(NULL);
// デモ用に "90秒後" の時刻を作る
// 実際には処理を行った後に time(NULL) を再度呼びます
time_t end = start + 90;
// 秒差を計算
double diff = difftime(end, start);
// 結果を表示(小数なし)
printf("2つの時刻の差は %.0f 秒です。\n", diff);
return 0;
}
2つの時刻の差は 90 秒です。
実務ではendに加算せず、処理の前後でそれぞれtime(NULL)を呼びます。
経過時間(秒)を測るシンプルな例
次は、処理の経過時間を実際に測る例です。
ここでは分かりやすさのため、difftime自身を使って約2秒待つ簡単なループを利用します(いわゆるビジーウェイト。デモ用であり実務では非推奨)。
#include <stdio.h>
#include <time.h>
int main(void) {
// 計測開始時刻
time_t start = time(NULL);
// おおよそ2秒経過するまで待機(ビジーウェイト)
// 実務では sleep や thrd_sleep などの待機APIを検討してください
while (difftime(time(NULL), start) < 2.0) {
// 何もしない(デモ用の待機)
}
// 計測終了時刻
time_t end = time(NULL);
// 経過秒を計算
double elapsed = difftime(end, start);
// 結果を表示
printf("経過時間: %.0f 秒\n", elapsed);
return 0;
}
経過時間: 2 秒
経過時間の測定は「開始」「終了」「difftimeで差を取る」の3ステップが基本です。
difftimeの注意点
time_tの直接の引き算を避ける理由
time_t同士を直接引き算するのは避け、必ずdifftimeを使いましょう。
time_tは実装依存で、符号付きか符号なし、ビット幅などが環境で異なるため、単純な減算は思わぬ不具合の原因になります。
よくある落とし穴と影響
| 理由 | 起こりうる問題 |
|---|---|
time_tの符号が実装依存 | 負の差を扱えない環境で桁あふれや巨大値になる |
| ビット幅が実装依存(32/64bitなど) | 減算時にオーバーフローや符号反転を招く |
| 中間計算の型が未定義になりやすい | 最終的なdoubleへの変換で誤った値になる |
difftimeはこれらの違いを吸収するために用意された標準関数です。
望ましい書き方の比較
// 悪い例(直接引き算): 実装によっては未定義動作や誤動作の可能性
// long long sec = end - start;
// 良い例: difftimeで安全に差分を得る
double sec = difftime(end, start);
負の値が返るケース
第1引数の時刻が第2引数より過去であれば、difftimeは負の値を返します。
比較や方向判定に便利です。
簡単な確認例
#include <stdio.h>
#include <time.h>
int main(void) {
time_t a = time(NULL);
time_t b = a + 10; // aの10秒後
// あえて順序を逆にして差を取る
double d = difftime(a, b); // a - b = -10
if (d < 0.0) {
printf("aはbより %.0f 秒だけ過去です。\n", -d);
} else {
printf("aはbと同時刻か未来です。\n");
}
return 0;
}
aはbより 10 秒だけ過去です。
順序を明確にし、負値が想定通りか常に意識しましょう。
移植性と精度のポイント
difftimeは移植性を高めますが、精度や範囲には実装依存の側面があります。
押さえておきたい事項
time_tの範囲: 32bit環境では2038年問題があり得ます。64bittime_tでは広い範囲を表せますが、そもそもtime_tに表現できない時刻は扱えません。
doubleの丸め: doubleは約15〜16桁の有効桁を持ちます。日常的な計測範囲では問題になりにくいですが、非常に大きな差(数十万年規模)では厳密な整数性が崩れる可能性があります。
サブ秒精度: 標準のtime関数は整数秒単位の現在時刻を返す実装が多く、difftimeの結果も通常は整数秒です。サブ秒(ミリ秒など)の精密計測が必要な場合は、別のAPI(例: POSIXのclock_gettime)の検討が必要です。
まとめ
difftimeは、2つのtime_tの差を安全かつ移植性高く「秒」で得られる標準関数です。
使い方はdifftime(end, start)とシンプルで、表示はprintf("%.0f")などで調整できます。
直接の引き算は避ける、負の値の扱いに注意する、精度や範囲の限界を理解する、といったポイントを押さえれば、初心者の方でも確実に経過時間や時刻差を扱えるようになります。
実務では要件に合わせて丸め方を決め、必要なら高精度の計時APIを併用してください。
