はじめに
プリザンターのサーバスクリプトだと、日付項目などのDateTime型はタイムゾーンはUTCのデータしか取得が出来ません。
これは、サーバスクリプトの実装に使われているClearScriptのライブラリの制約によるもので、C#のDateTime型をJavaScriptのDateTime型に変換をおこなうときに、タイムゾーンがUTCとなってしまうためです。
EnableDateTimeConversion
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.
ただし、気をつけないといけないことが一つあります。サーバスクリプト内で日付の書き換え行う場合など、DateTimeの更新などを行う場合は、それを実行するユーザーにセットされているタイムゾーンのデータをセットする必要があります。
どこでどのタイムゾーンになるか簡単にまとめてみました。
実行環境 | データベース | ユーザー設定 | API Get/Set1 | スクリプトGet/Set2 | サーバスクリプトGet | サーバスクリプトSet2 |
---|---|---|---|---|---|---|
JST | JST | JST | JST | JST | UTC | JST |
UTC | UTC | JST | JST | JST | UTC | JST |
普通に日本向けに運用している場合などは、何をするにしても一旦JSTに変換する必要がありかなりめんどくさい・・・。
解決してみた
サーバスクリプトに実装してみた
サーバスクリプトから取得するときだけ、UTCになるのが不便なので、一括でタイムゾーンを変換してやりましょう。
model
を直接触ると面倒なので、DateTimeなプロパティだけをmodel_jst
という変数を作ってそちらにセットしてみます。「画面表示の前」や「秒表示の前」にセットすればOKです。
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~Z
とDate001~999
、UpdateTime
とCreatedTime
のうちページに表されているもの(=modelに含まれているもの)だけが、model_jstにセットされます。表示されていないものを触りたいときはview.AlwaysGetColumnsを使って対象を追加する方法も吊しのまま使えるようになっています。
デバッグ用にcontext.Log
を追加して実行してみるとこんな感じになります。
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
お、いい感じに変換できてますね。
拡張サーバスクリプトにしてみた
それぞれのサイトに追加していくもの面倒なので、拡張サーバスクリプトにして組み込んでみました。
{
"Name": "modelのタイムゾーンを変換する",
"BeforeOpeningPage": true,
"BeforeOpeningRow": true,
"Body": "// Write an arbitrary script."
}
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で囲っています。また、正常に実行されることを確認するために、success_model_jst
に実行に成功したかどうかをtrue/false
でセットしています。
まとめ
サーバスクリプトで常に頭を悩ませるタイムゾーン問題を簡単に解決してみました。マルチロケーションで異なるタイムゾーンのユーザーが混在している環境の場合は、user.UserId
で実行ユーザのIDを取得した後にAPIのusers/get
でユーザーのTimeZone
とLanguage
3を取得することで対応が可能です。