DateTime の書式設定 - ToString と標準フォーマット
DateTime オブジェクトを文字列に変換するとき、ToString メソッドにフォーマット指定子を渡すことで出力形式を自由にコントロールできる。C# には標準フォーマット指定子とカスタムフォーマット指定子の 2 種類が用意されており、用途に応じて使い分ける。
ToString の基本
DateTime の ToString を引数なしで呼ぶと、実行環境のカルチャに依存した文字列が返る。
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString());
// 例: 2025/02/15 14:30:45(日本語環境の場合)これは環境によって出力が変わるため、ログやデータ保存には向かない。明示的にフォーマットを指定する習慣をつけておくのが重要だ。
DateTime now = DateTime.Now;
// フォーマット指定子を渡す
Console.WriteLine(now.ToString("yyyy-MM-dd"));
// 出力: 2025-02-15
Console.WriteLine(now.ToString("HH:mm:ss"));
// 出力: 14:30:45ToString の引数に渡す文字列がフォーマット指定子であり、これが書式設定の中心となる。
標準フォーマット指定子
標準フォーマット指定子は 1 文字のアルファベットで、よく使われる書式があらかじめ定義されている。
| 指定子 | 意味 | 出力例 |
|---|---|---|
| d | 短い日付 | 2025/02/15 |
| D | 長い日付 | 2025年2月15日 |
| t | 短い時刻 | 14:30 |
| T | 長い時刻 | 14:30:45 |
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString("d")); // 2025/02/15
Console.WriteLine(now.ToString("D")); // 2025年2月15日
Console.WriteLine(now.ToString("t")); // 14:30
Console.WriteLine(now.ToString("T")); // 14:30:45日付と時刻を組み合わせた指定子もある。
| 指定子 | 意味 | 出力例 |
|---|---|---|
| f | 長い日付 + 短い時刻 | 2025年2月15日 14:30 |
| F | 長い日付 + 長い時刻 | 2025年2月15日 14:30:45 |
| g | 短い日付 + 短い時刻 | 2025/02/15 14:30 |
| G | 短い日付 + 長い時刻 | 2025/02/15 14:30:45 |
ここで注意すべきなのは、標準フォーマット指定子の出力がカルチャに依存するという点だ。同じ “d” でも、日本語環境では 2025/02/15、英語環境では 2/15/2025 のように変わる。
カルチャを明示する
環境に依存しない出力が必要な場合は、CultureInfo を明示的に渡す。
using System.Globalization;
DateTime now = DateTime.Now;
// 日本のカルチャを指定
var ja = new CultureInfo("ja-JP");
Console.WriteLine(now.ToString("D", ja));
// 出力: 2025年2月15日
// 米国のカルチャを指定
var en = new CultureInfo("en-US");
Console.WriteLine(now.ToString("D", en));
// 出力: Saturday, February 15, 2025実行環境のカルチャに依存する。開発マシンと本番サーバーで結果が異なる可能性がある。
出力が一貫する。国際化対応やログ出力では必須の手法。
カスタムフォーマット指定子
標準フォーマット指定子で対応できない形式が必要なときは、カスタムフォーマット指定子を組み合わせて自由に書式を定義する。
| 指定子 | 意味 | 例 |
|---|---|---|
| yyyy | 4 桁の年 | 2025 |
| MM | 2 桁の月 | 02 |
| dd | 2 桁の日 | 15 |
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString("yyyy/MM/dd"));
// 出力: 2025/02/15
Console.WriteLine(now.ToString("yyyy年M月d日"));
// 出力: 2025年2月15日
Console.WriteLine(now.ToString("yyyyMMdd_HHmmss"));
// 出力: 20250215_143045M と MM、d と dd の違いは、先頭のゼロ埋めを行うかどうかにある。MM は常に 2 桁(02)になるのに対し、M は不要なゼロを省略する(2)。ファイル名やデータベースのキーには MM/dd のゼロ埋め形式が適しており、ユーザー向け表示には M/d のほうが自然に見える。
時刻のカスタム指定子も見ておこう。
| 指定子 | 意味 | 例 |
|---|---|---|
| HH | 24 時間制(2 桁) | 14 |
| hh | 12 時間制(2 桁) | 02 |
| mm | 分(2 桁) | 30 |
| ss | 秒(2 桁) | 45 |
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString("HH:mm:ss"));
// 出力: 14:30:45
Console.WriteLine(now.ToString("hh:mm tt"));
// 出力: 02:30 PM(英語環境)HH が 24 時間制、hh が 12 時間制という区別は見落としやすい。大文字と小文字で意味が変わるのは C# のフォーマット指定子全般に共通する特徴であり、mm(分)と MM(月)の取り違えにも注意が必要だ。
ISO 8601 形式での出力
API 通信やログ出力では、国際標準である ISO 8601 形式が頻繁に使われる。標準フォーマット指定子 “o”(ラウンドトリップ)を使うと、精度を失わずに DateTime を文字列化できる。
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString("o"));
// 出力: 2025-02-15T14:30:45.1234567+09:00
Console.WriteLine(now.ToString("s"));
// 出力: 2025-02-15T14:30:45タイムゾーン情報とミリ秒以下の精度を保持する。DateTime.Parse で復元しても情報が失われない。
ISO 8601 の基本形式で、タイムゾーン情報は含まない。文字列としてのソートが可能。
“o” 指定子は DateTime の Kind(Local / Utc / Unspecified)に応じてタイムゾーンオフセットの出力が変わる。Local なら +09:00 のようなオフセットが付き、Utc なら Z が付く。Unspecified の場合はオフセットが省略される。
文字列補間での利用
C# 6 以降の文字列補間($“”)でも、コロンの後にフォーマット指定子を書ける。
DateTime now = DateTime.Now;
string message = $"現在時刻: {now:yyyy-MM-dd HH:mm}";
Console.WriteLine(message);
// 出力: 現在時刻: 2025-02-15 14:30
string log = $"[{now:HH:mm:ss.fff}] 処理開始";
Console.WriteLine(log);
// 出力: [14:30:45.123] 処理開始ToString を明示的に呼ばなくても、補間式の中でフォーマット指定子を直接記述できるため、コードが簡潔になる。実務では ToString よりもこちらの書き方を目にする機会が多いだろう。
DateTime.Now.ToString("MM") と DateTime.Now.ToString("mm") の違いとして正しいものはどれか。
- どちらも月を返すが、桁数が異なる
- MM は月を、mm は分を返す
- MM は大文字の月名を、mm は小文字の月名を返す
- 違いはなく、どちらも同じ結果を返す
MM は月(Month)、mm は分(Minute)を表す。大文字と小文字で意味が完全に変わるため、フォーマット指定子では常にケースに注意する必要がある。