CodeGym /コース /C# SELF /タイムゾーンの扱い方: TimeZoneInfo<...

タイムゾーンの扱い方: TimeZoneInfo

C# SELF
レベル 15 , レッスン 2
使用可能

1. はじめに

タイムゾーンって「何時間か足す/引く」だけだと思ってるなら、すぐに世界中のプログラマーが感じてる痛みを味わうことになるよ。タイムゾーン、夏時間/冬時間の切り替え、他の地域に「時間を変換」しようとした時の予期しない例外…全部バグの元で、見つけるのも説明するのも超大変。

一番ヤバいのは、「世界共通の時間の考え方」なんてものは存在しないってこと。例えば、隣同士の国でも夏時間の扱いが違ったり、年の途中で突然ルールが変わったり(マジである!)。例:2011年にサモアは日付変更線をまたいで丸一日飛ばしたんだ。

でもC#.NETには、なんとか戦うための強力なツールがある。今日は救世主TimeZoneInfo型とその機能を紹介するよ。これで君と君のアプリも助かるはず!

タイムゾーン対応が必要なとき

  • ユーザーやサーバーが世界中のいろんな地域にいるとき
  • DBに日付と時間をUTCで保存して、ユーザーにはローカル時間で見せたいとき
  • スケジュール、リマインダー、オンラインイベントの計算(「ウェビナーはベルリン時間19:00開始―君の地域だと何時?」)
  • グローバル/企業向けシステム開発時(例:国際ビジネス向け会計やCRMなど)

TimeZoneInfo型のざっくり紹介

TimeZoneInfoは.NETで用意された、タイムゾーン情報(UTCからのオフセット、名前、夏時間対応など)を表すためのクラスだよ。

古いTimeZoneクラスは「ローカル」と「UTC」しか知らないけど、TimeZoneInfoならシステムに登録されてる全タイムゾーン(手動で作ったやつも!)にちゃんとアクセスできる。

2. タイムゾーン情報の取得

ローカルとUTCのタイムゾーン

ローカルタイムゾーンの情報を取得するのは超カンタン:


// ローカル(つまり今プログラムが動いてる場所)
TimeZoneInfo local = TimeZoneInfo.Local;

// いつでもUTC
TimeZoneInfo utc = TimeZoneInfo.Utc;

Console.WriteLine(local.DisplayName); // 例: (UTC+01:00) Berlin, Vienna
Console.WriteLine(utc.DisplayName);   // (UTC) Coordinated Universal Time

利用可能な全タイムゾーン

ユーザーに全タイムゾーン一覧を見せたい時(例:サービス登録時)によく使う:


foreach (var tz in TimeZoneInfo.GetSystemTimeZones())
{
    Console.WriteLine($"{tz.Id} | {tz.DisplayName}");
}

こんな感じでリストが出る:

  • Central European Standard Time | (UTC+01:00) Berlin, Vienna
  • Pacific Standard Time | (UTC-08:00) Pacific Time (US & Canada)
  • などなど

ビジュアル:TimeZoneInfoの主なプロパティ

プロパティ 説明
Id
タイムゾーンのシステムID(検索時に使う)
DisplayName
ユーザー向けの説明(時差や都市名付き)
StandardName
「標準時間」の名前
DaylightName
夏時間用の名前
BaseUtcOffset
UTCからのオフセット(例:ベルリンなら+01:00)
SupportsDaylightSavingTime
夏時間/冬時間の切り替えに対応してるならTrue

3. タイムゾーン間の時間変換

ここが本題!やりたいことは:

  • あるゾーンの時間を別のゾーンに変換(例:サーバーはUTCで記録、ユーザーにはローカルで表示)
  • 夏時間/冬時間の切り替えもちゃんと考慮

基本の書き方


DateTime utcNow = DateTime.UtcNow;

// 例えばこれを中央ヨーロッパ時間に変換
TimeZoneInfo europeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTime europeTime = TimeZoneInfo.ConvertTimeFromUtc(utcNow, europeZone);

Console.WriteLine($"UTC now: {utcNow}");       // 2024-06-20 10:30:00
Console.WriteLine($"Europe now: {europeTime}"); // 2024-06-20 11:30:00

重要:内部計算や保存には必ずUTCを使って、「出力時」だけ必要なゾーンに変換しよう!

タイムゾーンIDの調べ方

WindowsだとタイムゾーンのID(Id)は独自(例:"Central European Standard Time")、Linux/UnixだとIANA/Olson ID("Europe/Berlin", "America/New_York")が多いよ。

システム内のID一覧はTimeZoneInfo.GetSystemTimeZones()で取得できる。

4. 任意のゾーン間での変換

例えばロンドン(GMT/UTC+0)の時間を東京(UTC+9)に変換したい場合:


DateTime londonTime = new DateTime(2024, 6, 20, 12, 0, 0, DateTimeKind.Unspecified);

TimeZoneInfo londonZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
TimeZoneInfo tokyoZone  = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");

// まずローカル時間をUTCに変換
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(londonTime, londonZone);

// 次にUTCを東京時間に変換
DateTime tokyoTime = TimeZoneInfo.ConvertTimeFromUtc(utc, tokyoZone);

Console.WriteLine($"London: {londonTime} | UTC: {utc} | Tokyo: {tokyoTime}");

夏時間・冬時間の切り替え対応

TimeZoneInfoは、必要なゾーンが対応していれば夏時間/冬時間の切り替えもちゃんと考慮してくれる。


TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

DateTime dateWinter = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Unspecified);
DateTime dateSummer = new DateTime(2024, 7, 1, 12, 0, 0, DateTimeKind.Unspecified);

Console.WriteLine( TimeZoneInfo.ConvertTimeToUtc(dateWinter, eastern)); // UTC-5のオフセット
Console.WriteLine( TimeZoneInfo.ConvertTimeToUtc(dateSummer, eastern)); // UTC-4のオフセット―夏時間!

ちなみに、もしアメリカ(上の例)が夏時間を廃止しても(毎年そんな話が出る!)、OSのタイムゾーンDBはちゃんと更新されるから、君のコードも正しく動くよ。

5. 実践アドバイス&よくあるミス

例外と落とし穴

  • 夏時間/冬時間の切り替え時(例:切り替え日の夜2:30)は「存在しない」または「重複する」時間が発生することがある:
    例えば「戻す」日の2:30は2回発生して、どっちも「違う」2:30になる。
  • タイムゾーン一覧はOSのアップデートで変わることがあるので注意!例:ある国が夏時間を廃止/導入した場合など。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION