はじめに
プリザンターの API で日時を送受信するとき、そのタイムゾーンはどうやって決まるのでしょうか。DB にはタイムゾーン情報なしの DateTime が格納されているため、API 側で何らかの基準が必要になります。
本記事では、API での日時変換の仕組みと、知っておくべきポイントを紹介します。
| 回 | テーマ |
|---|---|
| 第 1 回 | アーキテクチャ編 — 全体設計と変換の仕組み |
| 第 2 回 | サーバスクリプト編 — SS 固有の変換方式と注意点 |
| 第 3 回(本記事) | API 編 — API でのタイムゾーンの取り扱い |
| 第 4 回 | タイムゾーン混在環境編 — ユーザーのタイムゾーンが混在する場合の問題と対策 |
バージョン 1.5.1.0 を対象にしています
API のタイムゾーン基準
API の日時処理で最も重要なポイントは、API キーに紐づくユーザーのタイムゾーンが基準になるということです。
リクエスト側でタイムゾーンを指定する手段はありません。同じ日時文字列を送信しても、API キーの所有ユーザーのタイムゾーン設定によって異なるサーバーローカル日時に変換されます。
API リクエスト時の変換フロー
API でレコードを作成・更新する際の日時変換は、フォーム入力と同じ ToUniversal(context) が使われます。
例えば API キーの所有ユーザーのタイムゾーンが JST(+9)で、サーバータイムゾーンが UTC の場合、"2024/01/15 09:00" という入力値は 2024/01/15 00:00(UTC)として DB に保存されます。
API レスポンス時の変換フロー
API レスポンスでも、API キーの所有ユーザーのタイムゾーンで日時が返却されます。
入力と出力で対称的な変換が行われるため、同じ API キーで操作する限り日時のズレは発生しません。
API キーのユーザータイムゾーンが異なる場合
ここで気をつけたいのが、異なるタイムゾーンのユーザーが同じレコードを API 経由で操作するケースです。
例: ユーザー A(JST)で登録、ユーザー B(PST)で取得
これは日時として正しい変換です。JST の 1/15 09:00 と PST の 1/14 16:00 は同じ瞬間を指しています。ただし、日付のみのフィールド(Ymd 形式)では日付が変わってしまうことがあり、これは第 4 回で詳しく扱います。
CSV インポートのタイムゾーン
CSV インポートも API と同様に、インポート実行ユーザーのタイムゾーンで日時が解釈されます。
else if (TypeName == "datetime")
{
return value?.ToDateTime(format: RecordingFormat)
.ToUniversal(context: context).ToString()
?? string.Empty;
}
context はインポートを実行したユーザーのコンテキストです。つまり同じ CSV ファイルでも、インポートするユーザーのタイムゾーンが異なれば、DB に格納される日時が変わります。
例: 同じ CSV を異なるタイムゾーンのユーザーがインポート
| CSV の値 | ユーザータイムゾーン | ToUniversal 結果(サーバータイムゾーン=UTC) | DB 値 |
|---|---|---|---|
2024/01/15 09:00 |
JST (+9) | 2024/01/15 00:00 | 2024/01/15 00:00 |
2024/01/15 09:00 |
PST (-8) | 2024/01/15 17:00 | 2024/01/15 17:00 |
同じ 09:00 という値でも、ユーザータイムゾーンによって DB に格納される値が異なります。
CSV インポートを行う際は、CSV 内の日時がどのタイムゾーンを想定しているかを意識し、インポート実行ユーザーのタイムゾーン設定を確認しましょう。
API 連携時の実践的な注意点
1. API キーのタイムゾーンを統一する
外部システムとの連携で複数の API キーを使う場合、すべての API キーのユーザータイムゾーンを統一することで日時の混乱を防げます。
2. サーバータイムゾーンと API ユーザータイムゾーンを合わせる
API キーの所有ユーザーのタイムゾーンがサーバーローカルタイムゾーンと同一であれば、ToUniversal / ToLocal がスキップされ、送信した日時がそのまま DB に格納されます。
public static DateTime ToUniversal(this DateTime value, Context context)
{
var timeZoneInfo = context.TimeZoneInfo;
if (timeZoneInfo == null || timeZoneInfo.Id == TimeZoneInfo.Local.Id)
return value; // 同一タイムゾーンならスキップ
return TimeZoneInfo.ConvertTime(value, timeZoneInfo, TimeZoneInfo.Local);
}
3. 日時形式に注意する
API で日時を送信する際は、プリザンターが受け付ける形式で指定します。タイムゾーン情報(Z や +09:00 など)を付与しても、リクエスト内のタイムゾーン情報は無視され、API キーのユーザータイムゾーンが使われます。
4. バックグラウンド処理のタイムゾーン
バックグラウンドサーバスクリプトのスケジュール評価では、以下の優先順位でタイムゾーンが決定されます。
| 優先順位 | 設定値 | 説明 |
|---|---|---|
| 1 | schedule.ScheduleTimeZoneId |
スケジュール個別設定 |
| 2 | TimeZoneDefault |
Service.json のシステムデフォルト |
| 3 | UTC | いずれも未設定時のフォールバック |
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(
!schedule.ScheduleTimeZoneId.IsNullOrEmpty()
? schedule.ScheduleTimeZoneId
: !Parameters.Service.TimeZoneDefault.IsNullOrEmpty()
? Parameters.Service.TimeZoneDefault
: TimeZoneInfo.Utc.Id);
フロントエンドへのタイムゾーン情報伝達
補足として、画面表示の際にはユーザータイムゾーンの情報がフロントエンドにも伝達されています。
.Hidden(
controlId: "TimeZoneOffset",
value: context.TimeZoneInfoOffset()) // 例: "+09:00"
この値は HTML の hidden 要素として埋め込まれ、フロントエンドの JavaScript で日付ピッカーなどの表示補正に使用されます。API 連携ではこの仕組みは無関係ですが、タイムゾーン情報の伝達方法として知っておくと役立ちます。
入力経路ごとのタイムゾーン基準の比較
ここまでの内容を含め、各入力経路でタイムゾーン基準がどう決まるかをまとめます。
| 入力経路 | タイムゾーン基準の決定要因 | 注意点 |
|---|---|---|
| フォーム入力 | ログインユーザーのタイムゾーン | ユーザーの画面操作なので直感的 |
| API リクエスト | API キー所有ユーザーのタイムゾーン | リクエスト側でタイムゾーン指定不可 |
| CSV インポート | インポート実行ユーザーのタイムゾーン | CSV 内の日時がどのタイムゾーンかを意識 |
| サーバスクリプト(通常) | UTC 固定 | ユーザータイムゾーンを一切使わない |
| 計算式サーバスクリプト | 操作ユーザーのタイムゾーン | フォーム入力と同じ方式 |
まとめ
API でのタイムゾーン処理のポイントをまとめます。
- API では API キーに紐づくユーザーのタイムゾーンが基準になる
- リクエスト側でタイムゾーンを指定する手段はない
- 入出力は
ToUniversal/ToLocalで対称変換されるため、同じ API キーで操作する限り日時のズレは発生しない - CSV インポートもインポート実行ユーザーのタイムゾーンが基準になる
- 外部連携では API キーのタイムゾーンを統一するのが安全