C# Tips | 日付・時間処理:日付パース

C# C#
スポンサーリンク

はじめに 「日付パース」は“文字列を本物の日時に戻す”作業

さっきまで「日付フォーマット」で
DateTime → 文字列 に変換する話をしました。

今度は逆向き、
「文字列 → DateTime / DateTimeOffset」 に変換するのが「日付パース」です。

画面入力、CSV、外部API、設定ファイル…
現実の業務では、日時はまず「文字列」でやってきます。
それをちゃんと「日時」として理解できる形に戻さないと、
比較も計算も何もできません。

ここでは、初心者向けに

  • ParseTryParse の違い
  • 書式を指定する 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 は、
DateTimeKindUnspecified にすることが多いです。

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かローカルか、オフセット付きかを意識し、DateTimeStylesDateTimeOffset を使い分けること。
  • 用途ごとのパース処理をユーティリティにまとめ、メソッド名で「何をパースしているか」が分かるようにしておくこと。

ここを押さえておくと、
「なんとなく Parse している」状態から一歩進んで、
“外部データに強くて、バグりにくい日付パースユーティリティ”を
自分のC#コードの中に自然に組み込めるようになっていきます。

タイトルとURLをコピーしました