Ignite UI for Blazor が提供する日付ピッカーコンポーネント、IgbDatePicker ですが、このコンポーネント上で選択した日付値は、Blazor Server でホストされている場合でも、サーバーのローカルタイムゾーンに関係なく、ブラウザのローカルタイムゾーンにおける選択日付 + 午前0時として扱われます。
その結果、例えば米国・太平洋時間 (UTC-8) のタイムゾーンで稼働している Blazor Server に、日本のタイムゾーン (UTC+9) で稼働している PC のブラウザからアクセスし、その Blazor Server アプリケーション上の IgbDatePicker で何か日付を選択すると、日本における選択した日付 + 午前0時は、太平洋時間では前日の午前7時に該当するため、この前日の午前7時のローカル日時を指す DateTime オブジェクトが選択結果として Blazor Server 側に格納されます (下図例)。
もちろん、この動作仕様で妥当な場合も多いと思われます。しかし、IgbDatePicker 上に表示された「日付」を、文字どおりにサーバー側でも扱いたい、という場合は、このままでは困ったことになります。
本ナレッジベース記事を作成時点では、IgbDatePicker からはこのシナリオをサポートする直接の機能は用意がありません。そのため、「IgbDatePicker 上に表示された日付を、文字どおりにサーバー側ローカル時刻として扱いたい」という場合は、以下の実装で対応します。
まずは、サーバー側からブラウザのタイムゾーンオフセットを取得するため、以下の内容の JavaScript プログラムを用意します。この例では time-zone.js というファイル名で、wwwroot フォルダ直下に保存することとします。
export const getTimezoneOffset = () => new Date().getTimezoneOffset();
次に、IgbDatePicker を貼り付けた Blazor Server 側のコードですが、前述のとおり、IgbDatePicker の既定の動作に任せられないため、@bind-Value によるバインドは使わず、値からコンポーネントへの Value パラメーターへの設定と、コンポーネントで選択された値を書き戻す用の ValueChanged コールバックの設定とにそれぞれ分けて実装します。
@inject IJSRuntime JSRuntime <IgbDatePicker Value="_value" ValueChanged="OnValueChanged" /> @code { private DateTime _value = DateTime.Today; private async ValueTask OnValueChanged() { // このあと中身を実装 } }
IgbDatePicker で日付が選択されたときに、その選択された日時 (繰り返しになりますが、ブラウザのタイムゾーンにおける午前0時の日時を、サーバーのタイムゾーンのローカル日時に換算したあとの DateTime 値) を引数に呼び出されるコールバックメソッドである、OnValueChanged メソッド内で、以下の実装を記述します。
private async Task OnValueChanged(DateTime value) { // ブラウザのタイムゾーンオフセット (分) を取得 await using var module = await JSRuntime.InvokeAsync<IJSObjectReference>( "import", "./time-zone.js"); var timezoneOffset = await module.InvokeAsync<int>("getTimezoneOffset"); // IgbDatePicker から送られてきた値 (このサーバー上でのローカル時刻) を、 // ブラウザ上のローカル時刻に復元 var browserLocalTime = value.ToUniversalTime().AddMinutes(-timezoneOffset); // その上で、年・月・日だけを取り出して、サーバー上での 0:00AM のローカル時刻に変換 _value = new DateTime( browserLocalTime.Year, browserLocalTime.Month, browserLocalTime.Day, 0, 0, 0, DateTimeKind.Local); }
以上の実装で、どのようなタイムゾーンのブラウザからのアクセスであっても、画面上で選択した日付の、Blazor Server が稼働しているサーバー上のタイムゾーンにおけるローカル時刻午前 0 時を指す DateTime 値がサーバー側で格納できるようになります (下図)。
なお、上記サンプルコードは簡略化のため、JavaScript モジュールの参照を毎回破棄しています (await using 構文)。実際のプロダクションコードでは、処理性能上の観点から、オーナーとなるコンポーネントのフィールド変数に JavaScript モジュール参照をキャッシュし、適宜破棄するべきです。JavaScript モジュール参照のキャッシュと破棄も実装した完全なサンプルコードは以下のリンク先から参照いただけます。
また、以下のリンクから、GitHub Codespaces でこの Blazor Server によるサンプルプログラムを編集・実行することも可能です。