はじめに 「ログ用日時」は“あとから真実を追いかけるための命綱”
ログって、「とりあえず DateTime.Now 出しとけばいいでしょ?」で済ませがちなんですが、
本気でトラブル調査をしようとすると、
「タイムゾーンは?」「フォーマットは?」「ミリ秒は?」「機械が読める?人も読める?」
みたいな細かいところが効いてきます。
だからこそ、「ログ用日時生成」はユーティリティとして“型”を決めておく価値が高いです。
ここでは、初心者向けに
- 何を基準に時間を取るか(
Now/UtcNow) - どんなフォーマットで文字列にするか
- ミリ秒・タイムゾーン・一貫性をどう扱うか
を、実務目線でかみ砕いて説明していきます。
基本方針:ログは「UTC基準+フォーマット固定」が鉄板
なぜ DateTime.Now ではなく UtcNow を使うのか
ログは、あとから「いろんなサーバー」「いろんなタイムゾーン」の情報をまとめて見ることが多いです。
このとき、各サーバーがローカル時間(DateTime.Now)でバラバラに出していると、
「どっちが先に起きた?」「サマータイムで1時間ずれてない?」が分かりにくくなります。
そこで、ログの“内部的な基準”は UTC にそろえるのが定番です。
DateTime utcNow = DateTime.UtcNow;
C#ただし、人間が直接ログファイルを見ることも多いので、
「UTC だけだと直感的に読みにくい」という問題もあります。
なので実務では、
- 内部的には UTC を使う
- 文字列としては「UTC であることが分かるフォーマット」にする
という方針を取ることが多いです。
実務で使いやすいフォーマット:ISO 8601 風の文字列
yyyy-MM-ddTHH:mm:ss.fffZ の形を覚えてしまう
ログ用の日時文字列として、ほぼ“世界標準”になっているのが
ISO 8601 風のフォーマットです。
例えばこんな形です。
2026-02-18T11:23:45.123Z
意味はこうです。
2026-02-18… 日付T… 日付と時刻の区切り11:23:45.123… 時刻(ミリ秒まで)Z… UTC(Zulu time)であることを示す
C# でこの形の文字列を出すユーティリティを作ってみましょう。
using System;
using System.Globalization;
public static class LogTimeUtil
{
public static string GetLogTimestampUtc()
{
DateTime utcNow = DateTime.UtcNow;
return utcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture);
}
}
C#使い方の例です。
string ts = LogTimeUtil.GetLogTimestampUtc();
Console.WriteLine(ts); // 2026-02-18T11:23:45.123Z
C#ここでの重要ポイントは、
UtcNowを使っていること- フォーマットを固定していること
CultureInfo.InvariantCultureを指定して、環境によって変わらないようにしていること
です。
ローカル時間も欲しい場合の設計
「人間が読む用」と「機械が読む用」を分ける
運用現場では、「日本時間で見たい」「サーバーのローカル時間で見たい」
というニーズもよくあります。
その場合は、
「機械が読む用(UTC)」と「人間が読む用(ローカル)」を両方出す、
という設計もアリです。
public static class LogTimeUtil
{
public static string GetLogTimestampUtc()
{
DateTime utcNow = DateTime.UtcNow;
return utcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture);
}
public static string GetLogTimestampLocal()
{
DateTime localNow = DateTime.Now;
return localNow.ToString("yyyy-MM-dd HH:mm:ss.fff zzz", CultureInfo.InvariantCulture);
}
}
C#zzz は「タイムゾーンオフセット」(例:+09:00)を出してくれます。
Console.WriteLine(LogTimeUtil.GetLogTimestampUtc());
// 2026-02-18T11:23:45.123Z
Console.WriteLine(LogTimeUtil.GetLogTimestampLocal());
// 2026-02-18 20:23:45.123 +09:00
C#ログの1行を JSON などで出すなら、utc と local を両方持たせるのもよくあるパターンです。
ミリ秒をどうするか:切り捨てるか、そのまま使うか
「ミリ秒まで必要か?」を一度ちゃんと考える
ログの粒度によっては、「ミリ秒まで要らない」こともあります。
例えば、1秒に1回しかログが出ないなら、ミリ秒はノイズです。
その場合は、ログ用日時を生成するときにミリ秒を切り捨ててしまうのもアリです。
public static DateTime TruncateMilliseconds(DateTime dt)
{
return new DateTime(
dt.Year,
dt.Month,
dt.Day,
dt.Hour,
dt.Minute,
dt.Second,
0,
dt.Kind);
}
public static string GetLogTimestampUtcSecond()
{
DateTime utcNow = TruncateMilliseconds(DateTime.UtcNow);
return utcNow.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'", CultureInfo.InvariantCulture);
}
C#使い方の例です。
Console.WriteLine(GetLogTimestampUtcSecond());
// 2026-02-18T11:23:45Z
C#逆に、「高頻度ログ」「パフォーマンス計測」などでは、
ミリ秒(場合によってはもっと細かい単位)まで欲しくなります。
なので、
- 通常ログ → 秒単位
- 詳細トレース → ミリ秒単位
のように、用途ごとにユーティリティを分けておくのも良い設計です。
ログ用日時ユーティリティを“1箇所に集約する”意味
「あちこちでバラバラに DateTime.Now しない」
一番やってはいけないのは、
プロジェクトのあちこちで好き勝手に
DateTime.Now.ToString()
C#みたいなことをしてしまうことです。
これをやると、
- サーバーごとにフォーマットが違う
- ロケールによって「2026/02/18」だったり「18.02.2026」だったりする
- タイムゾーンが分からない
- ミリ秒があったりなかったりする
という“カオスログ”が生まれます。
だからこそ、
public static class LogTimeUtil
{
public static string NowUtc() { ... }
public static string NowLocal() { ... }
public static string NowUtcSecond() { ... }
}
C#のように、「ログ用日時は必ずここを通す」という“入り口”を1箇所に決めておくことが大事です。
まとめ 「ログ用日時生成ユーティリティ」は“時間のルールをコードに刻む場所”
ログ用日時は、ただの DateTime.Now ではなく、
「どのタイムゾーンで」「どんなフォーマットで」「どの精度で」
という“時間のルール”そのものです。
押さえておきたいポイントを整理すると、こうなります。
- 基準は
DateTime.UtcNowにして、UTC であることが分かるフォーマット(...Z)にする CultureInfo.InvariantCultureを使って、環境に依存しない文字列を出す- 必要に応じてローカル時間版(
zzz付き)も用意し、「人が読む用」と「機械が読む用」を分ける - ミリ秒を使うかどうかは用途次第。秒単位版・ミリ秒版をユーティリティとして分けておくと扱いやすい
- プロジェクト全体で「ログ用日時は必ずこのユーティリティを通す」というルールにして、一貫性を守る
ここまで決めてしまえば、
「とりあえず DateTime.Now」から卒業して、
“トラブル調査や監査でちゃんと戦えるログ用日時”を、毎回迷わず生成できるようになります。
