はじめに 「日付パース」は“文字列を本物の日時に戻す”作業
さっきまで「日付フォーマット」でDateTime → 文字列 に変換する話をしました。
今度は逆向き、
「文字列 → DateTime / DateTimeOffset」 に変換するのが「日付パース」です。
画面入力、CSV、外部API、設定ファイル…
現実の業務では、日時はまず「文字列」でやってきます。
それをちゃんと「日時」として理解できる形に戻さないと、
比較も計算も何もできません。
ここでは、初心者向けに
ParseとTryParseの違い- 書式を指定する
ParseExact/TryParseExact - 実務で使えるユーティリティ化
- ありがちな落とし穴
を、例題を交えながらかみ砕いて説明します。
基本:DateTime.Parse と DateTime.TryParse
Parse は「失敗したら例外を投げる」タイプ
一番シンプルなパースは DateTime.Parse です。
using System;
string s1 = "2026/02/10 20:15";
DateTime dt1 = DateTime.Parse(s1);
Console.WriteLine(dt1); // 2026/02/10 20:15:00
C#日本の環境なら、"2026/02/10 20:15" のような文字列はだいたい解釈してくれます。
ただし、
「解釈できない文字列」が来ると例外になります。
string s2 = "2026-99-99";
DateTime dt2 = DateTime.Parse(s2); // FormatException が発生
C#業務システムで、ユーザー入力や外部データに対して
いきなり Parse を使うのは危険です。
例外が飛ぶ=落ちる可能性があるからです。
TryParse は「失敗しても例外を投げない」タイプ
そこで基本になるのが TryParse です。
string s = "2026/02/10 20:15";
if (DateTime.TryParse(s, out DateTime dt))
{
Console.WriteLine($"成功: {dt}");
}
else
{
Console.WriteLine("変換できませんでした");
}
C#TryParse は、
- 変換に成功 →
trueを返し、out変数に結果を入れる - 変換に失敗 →
falseを返し、例外は投げない
という、安全寄りのメソッドです。
ユーザー入力や外部データには、
基本的に TryParse 系を使うと覚えておいてください。
書式をきっちり決めたいときは ParseExact / TryParseExact
「この形式だけ受け付けたい」という場面
Parse / TryParse は「環境のカルチャに応じて、いい感じに解釈しようとする」メソッドです。
これは便利な反面、
「思ってもみない形式を受け入れてしまう」こともあります。
例えば、"02/03/2026" が「2月3日」なのか「3月2日」なのか、
カルチャによって解釈が変わることがあります。
業務で「この形式だけ!」と決めたいときは、ParseExact / TryParseExact を使います。
ParseExact の例
using System;
using System.Globalization;
string s = "2026-02-10 20:15";
DateTime dt = DateTime.ParseExact(
s,
"yyyy-MM-dd HH:mm",
CultureInfo.InvariantCulture
);
Console.WriteLine(dt); // 2026/02/10 20:15:00
C#ここで指定しているのは、
- 入力文字列:
"2026-02-10 20:15" - 書式文字列:
"yyyy-MM-dd HH:mm" - カルチャ:
CultureInfo.InvariantCulture(カルチャに依存しない固定ルール)
です。
書式が少しでも違うと、例外になります。
string bad = "2026/02/10 20:15"; // スラッシュ
DateTime dtBad = DateTime.ParseExact(
bad,
"yyyy-MM-dd HH:mm",
CultureInfo.InvariantCulture
); // FormatException
C#「厳密にこの形式だけ受け付けたい」なら ParseExact、
「失敗したら例外は困る」なら TryParseExact を使います。
TryParseExact の例
string s = "2026-02-10 20:15";
bool ok = DateTime.TryParseExact(
s,
"yyyy-MM-dd HH:mm",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out DateTime dt
);
if (ok)
{
Console.WriteLine($"成功: {dt}");
}
else
{
Console.WriteLine("書式が違います");
}
C#TryParseExact は、
「書式が合っていれば true、合っていなければ false」
という、とても分かりやすい動きです。
DateTimeOffset のパース(タイムゾーン付き)
オフセット付き文字列をパースする
APIやログでは、"2026-02-10T20:15:30+09:00" のように、
タイムゾーン(オフセット)付きの文字列がよく使われます。
これは DateTimeOffset でパースするのが自然です。
using System;
using System.Globalization;
string s = "2026-02-10T20:15:30+09:00";
DateTimeOffset dto = DateTimeOffset.ParseExact(
s,
"yyyy-MM-dd'T'HH:mm:sszzz",
CultureInfo.InvariantCulture
);
Console.WriteLine(dto); // 2026/02/10 20:15:30 +09:00
Console.WriteLine(dto.UtcDateTime); // 2026/02/10 11:15:30
C#書式のポイントは zzz です。+09:00 のようなオフセットを表します。
TryParseExact 版も同様に使えます。
実務ユーティリティとしてまとめる
「この形式をパースする」ことを名前で表現する
あちこちで
DateTime.ParseExact(s, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
DateTimeOffset.ParseExact(s, "yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
C#と書いていると、
「これは画面入力?CSV?API?」がコードから読み取りにくくなります。
用途ごとにメソッド名を付けたユーティリティにすると、
意図が一気に分かりやすくなります。
using System;
using System.Globalization;
public static class DateParseUtil
{
private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;
public static bool TryParseDisplayDateTime(string text, out DateTime result)
{
// 画面入力想定: 2026/02/10 20:15
return DateTime.TryParseExact(
text,
"yyyy/MM/dd HH:mm",
Invariant,
DateTimeStyles.None,
out result
);
}
public static bool TryParseApiTimestampUtc(string text, out DateTime result)
{
// API想定: 2026-02-10T11:15:30Z
return DateTime.TryParseExact(
text,
"yyyy-MM-dd'T'HH:mm:ss'Z'",
Invariant,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
out result
);
}
public static bool TryParseOffsetTimestamp(string text, out DateTimeOffset result)
{
// オフセット付き: 2026-02-10T20:15:30+09:00
return DateTimeOffset.TryParseExact(
text,
"yyyy-MM-dd'T'HH:mm:sszzz",
Invariant,
DateTimeStyles.None,
out result
);
}
}
C#使い方の例です。
if (DateParseUtil.TryParseDisplayDateTime("2026/02/10 20:15", out var dt))
{
Console.WriteLine($"画面入力OK: {dt}");
}
if (DateParseUtil.TryParseApiTimestampUtc("2026-02-10T11:15:30Z", out var utc))
{
Console.WriteLine($"API UTC: {utc} (Kind={utc.Kind})");
}
if (DateParseUtil.TryParseOffsetTimestamp("2026-02-10T20:15:30+09:00", out var dto))
{
Console.WriteLine($"オフセット付き: {dto} / UTC={dto.UtcDateTime}");
}
C#「何のためのパースか」がメソッド名に出ていることが、とても大事です。
これだけで、後から読む人の理解コストがかなり下がります。
ありがちな落とし穴と、その避け方
Parse だけに頼って例外だらけになる
ユーザー入力や外部データに対して Parse を使うと、
ちょっとした誤入力で FormatException が飛びます。
業務システムでは、
基本は TryParse / TryParseExact を使い、
失敗したら「エラーメッセージを出す」「スキップする」などの処理を書く
というスタイルにしておくと安定します。
カルチャ依存のパースに気づかない
DateTime.Parse("02/03/2026") のようなコードは、
実行環境のカルチャによって解釈が変わる可能性があります。
- 日本環境 → 2026年2月3日
- 米国環境 → 2026年3月2日
のようなズレが起こり得ます。
外部とのデータ連携やログ解析など、「意味がずれると困る」場面では、
必ず ParseExact / TryParseExact で書式を固定するのが安全です。
UTCかローカルかを意識せずにパースする
DateTime.Parse / ParseExact は、DateTimeKind を Unspecified にすることが多いです。
DateTimeStyles を指定しないと、
「これはUTCなのかローカルなのか」が曖昧なままになります。
例えば、"2026-02-10T11:15:30Z" のような
明らかにUTCな文字列をパースするときは、
DateTime.TryParseExact(
text,
"yyyy-MM-dd'T'HH:mm:ss'Z'",
Invariant,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
out var utc
);
C#のように、
「これはUTCとして扱う」と明示するのが大事です。
まとめ 「日付パースユーティリティ」は“外の世界の文字列を安全に受け止める玄関口」
日付パースは、
「外の世界からやってくる“文字列の日時”を、
システムの中でちゃんと扱える“本物の日時”に戻す」ための玄関口です。
押さえておきたいポイントは、
Parseは失敗すると例外、TryParseは失敗しても例外を投げないこと。- 書式をきっちり決めたいときは
ParseExact/TryParseExactを使い、書式文字列でルールを固定すること。 - APIやログのような機械向け文字列には、
CultureInfo.InvariantCultureと固定フォーマットを使うこと。 - UTCかローカルか、オフセット付きかを意識し、
DateTimeStylesやDateTimeOffsetを使い分けること。 - 用途ごとのパース処理をユーティリティにまとめ、メソッド名で「何をパースしているか」が分かるようにしておくこと。
ここを押さえておくと、
「なんとなく Parse している」状態から一歩進んで、
“外部データに強くて、バグりにくい日付パースユーティリティ”を
自分のC#コードの中に自然に組み込めるようになっていきます。
