Skip to content

日付の扱い ​

第5版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

サーバースクリプトで model から取得した日付(DateTime 型)は、実行環境やユーザー設定に関係なく UTC になります。一方、日付を書き込むときは実行ユーザーのタイムゾーンの値をセットする必要があります。このページでは、その理由と、取得した日付をまとめて日本時間に変換する方法を紹介します。

タイムゾーンの仕組み全体(DB・API・混在環境)は タイムゾーンの考え方 で詳しく扱っています。

取得した日付が UTC になる理由 ​

サーバースクリプトの実行には ClearScript が使われており、.NET の DateTime と JavaScript の Date は EnableDateTimeConversion フラグで自動変換されます。この変換は双方向ですが情報が落ちるもので、ClearScript のリファレンスには次のように書かれています。

Specifies that the script engine is to perform automatic conversion between .NET DateTime objects and JavaScript Date objects. This conversion is bidirectional and lossy. A DateTime object constructed from a JavaScript Date object always represents a Coordinated Universal Time (UTC) and has its Kind property set to Utc.

— V8ScriptEngineFlags Enumeration

どこでどのタイムゾーンになるか ​

実行環境データベースユーザー設定API Get/Setスクリプト Get/Setサーバースクリプト Getサーバースクリプト Set
JSTJSTJSTJSTJSTUTCJST
UTCUTCJSTJSTJSTUTCJST
  • API Get/Set のタイムゾーンは、API キーに紐づくユーザーのタイムゾーンと同じです。
  • スクリプト Get/Set とサーバースクリプト Set のタイムゾーンは、実行したユーザーのタイムゾーンと同じです。

日本向けに運用している場合、サーバースクリプトで取得した日付だけが UTC になるため、使う前に JST へ変換する必要があります。

model の日付をまとめて JST に変換する ​

model を直接書き換えるのではなく、日付系のプロパティだけを変換して model_jst という別の変数に入れます。条件は「画面表示の前」や「行表示の前」に設定します。

js
const regex = new RegExp('(^Date|Time$)');
let model_jst = {};

for (const [key, value] of Object.entries(model)) {
    if (regex.test(key) && value) {
        model_jst[key] = value.toLocaleString("ja-JP", {
             timeZone: "JST"
        });
    }
}

DateA〜DateZ、Date001〜Date999、UpdatedTime、CreatedTime のうち、画面に表示されているもの(= model に含まれているもの)だけが model_jst にセットされます。表示されていない項目も扱いたい場合は、view.AlwaysGetColumns で対象を追加すればそのまま使えます。

context.Log で変換前後を出力すると次のようになります。

text
model:CreatedTime/Thu Dec 05 2024 06:19:08 GMT+0000 (Coordinated Universal Time)
model:UpdatedTime/Thu Dec 05 2024 06:19:08 GMT+0000 (Coordinated Universal Time)
model:DateY/Wed Dec 04 2024 15:00:00 GMT+0000 (Coordinated Universal Time)
model:DateZ/Wed Dec 04 2024 15:00:00 GMT+0000 (Coordinated Universal Time)
model:Date001/Wed Dec 04 2024 15:00:00 GMT+0000 (Coordinated Universal Time)
model:Date002/Wed Dec 04 2024 15:00:00 GMT+0000 (Coordinated Universal Time)
model_jst:CreatedTime/2024/12/5 15:19:08
model_jst:UpdatedTime/2024/12/5 15:19:08
model_jst:DateY/2024/12/5 0:00:00
model_jst:DateZ/2024/12/5 0:00:00
model_jst:Date001/2024/12/5 0:00:00
model_jst:Date002/2024/12/5 0:00:00

拡張サーバースクリプトで全サイトに適用する ​

サイトごとに追加する代わりに、拡張サーバースクリプトとして組み込むこともできます。

json
{
    "Name": "modelのタイムゾーンを変換する",
    "BeforeOpeningPage": true,
    "BeforeOpeningRow": true,
    "Body": "// Write an arbitrary script."
}
js
let model_jst = {};
let success_model_jst = false;
//エラーが出ると面倒なのでtry-catchで囲っておく
try {
    const regex = new RegExp('(^Date|Time$)');
    for (const [key, value] of Object.entries(model)) {
        if (regex.test(key) && value) {
            model_jst[key] = value.toLocaleString("ja-JP", {
                timeZone: "JST"
            });
        }
    }
    success_model_jst = true;
} catch(e) {
    success_model_jst = false;
    context.Error(e.stack);
}

拡張サーバースクリプトでエラーが出ると処理全体が止まるため、try-catch で囲んでいます。catch で受け取る JavaScript のエラーオブジェクトのスタックトレースは小文字の e.stack です(e.Stack と書くと undefined になり、エラーメッセージが空になります)。context.Error() はメッセージを受け取ってエラーを設定するメソッドです(ServerScriptModelContext.cs)。変換が成功したかどうかは success_model_jst(true / false)で判定できます。

異なるタイムゾーンのユーザーが混在する場合 ​

context.UserId で実行ユーザーの ID を取得し、API の users/get でそのユーザーの TimeZone と Language を取得すれば対応できます(サーバースクリプトに user というオブジェクトは無いため、user.UserId と書くと動きません)。ただしロケールはプリザンターでは管理していないため、Language から推定してセットする必要があります。

実行ユーザーの言語とタイムゾーンは、API を使わずに context.Language と context.TimeZoneInfo でも取得できます。確認したソースでは、context.TimeZoneInfo は .NET の TimeZoneInfo を ToString() した表示名((UTC+09:00) ... の形式)で、toLocaleString の timeZone にそのまま渡せる IANA 形式(Asia/Tokyo など)ではありません(ServerScriptModel.cs)。

関連ページ ​

変更履歴

第5版記事の確認版を繰り返す表現を整理する
第4版本文から元記事や以前の版への言及を除き、正しい動作だけを書く形に整理
第3版「サーバースクリプト」を 1.5.8.1 のソースで検証して修正
第2版記事のファイル名に並び順の番号を付け、元記事リンクを frontmatter の sources に移行
第1版「サーバースクリプト」セクションの記事を追加