LoginSignup
3
2

More than 5 years have passed since last update.

Google App Maker + CalendarApp の日付フィルタ調整

Last updated at Posted at 2017-09-27

Google App Maker の CalendarSample

このサンプルの日付フィルタ機能を試すと、指定した開始日の前日夕方のイベントも表示されます。
逆に、指定した終了日の夕方以降のイベントが取得されません。

お察しの通り、ここにもタイムゾーンの問題がありました。
(念のため:2017年9月現在の話です。)

原因

サーバ側で動作するスクリプトの getEvents_() を見てみると、検索範囲の開始日と終了日の時刻を 00:00 にセットしている箇所があります。

[ServerScript]
function getEvents_(query) {
  var startDate = query.parameters.StartDate;
  startDate.setHours(0, 0, 0, 0); //<===========attn

  var endDate = query.parameters.EndDate;
  endDate.setDate(endDate.getDate() + 1);
  endDate.setHours(0, 0, 0, 0); //<===========attn

  if (startDate.getTime() > endDate.getTime()) {
    return [];
  }

  var results = [];
  var events = CalendarApp.getDefaultCalendar().getEvents(startDate, endDate);

重要なのは、サーバー側でスクリプトが動作する際、日付はすべて太平洋標準時PST(夏ならPDT)の扱いになっているという前提です。

そのため、startDate.setHours(0, 0, 0, 0) すると startDate は PST/PDT 00:00、つまり日本標準時JST 17:00(夏は16:00)にセットされます。

結果、対象カレンダーの予定が JST で作成されている場合、getEvents(startDate, endDate) は「開始日前日17:00 ~ 終了日当日17:00」(夏は 16:00)の検索結果を返してくる、というのが本現象の動きです。

対処

× ServerScript 内で日付を PST/PDT ⇒ JST へ変換して処理する
○ ClientScript 内であらかじめクエリ時刻を 00:00 に設定する

前者は、ユーザーが JST 環境限定ならよいのですが汎用性に欠けます。
まして、サーバーが今後も PST/PDT で動作を続ける保証もありません。

一方、クライアント側スクリプトはユーザーのタイムゾーンで動作します。
そのため 00:00 のセットはユーザー側で行うのが最良です。

初期化時の 00:00 セット

まず、サーバー側のスクリプトから setHours(0, 0, 0, 0) をコメントアウトしておきます。

[ServerScript]
function getEvents_(query) {
  var startDate = query.parameters.StartDate;
  //startDate.setHours(0, 0, 0, 0); //<===========comment-out

  var endDate = query.parameters.EndDate;
  endDate.setDate(endDate.getDate() + 1);
  //endDate.setHours(0, 0, 0, 0); //<===========comment-out

続いて、クライアント側スクリプトの loadEvents() より前に、「クエリ中の日時を 00:00 にセットし直す関数」を作成します。
本例では関数名を updateQueryDates() としましたが、お好みでどうぞ。

[ClientScript]
function updateQueryDates(){
  var ds = app.datasources.Events;

  //Copy dates from query params and set time to: 00:00
  var sd = new Date( ds.query.parameters.StartDate.getTime() );
  var ed = new Date( ds.query.parameters.EndDate.getTime() );
  sd.setHours( 0, 0, 0, 0 );
  ed.setHours( 0, 0, 0, 0 );

  //Set back to query
  ds.query.parameters.StartDate = sd;
  ds.query.parameters.EndDate = ed;
}

そして、loadEvents() 内では初期化後にこの関数を呼びます。

[ClientScript]
/**
 * Loads Events datasource.
 */
function loadEvents() {
  var ds = app.datasources.Events;
  ds.query.parameters.StartDate = new Date();
  ds.query.parameters.EndDate = new Date();
  updateQueryDates(); //<===========insert
  ds.load();
}

ここまでで、ロード時の初回検索は正常に動作するようになるはずです。

「初期化時に 00:00 をセットすれば?何故一度保存して上書きなんて面倒なことを?」
⇒後述の onValueEdit イベントでも同関数を利用する前提で、汎用化を図った結果です。
onValueEdit での処理を採用しない場合は、loadEvents() 内で new Date() したものを直接 setHours() で下処理するだけでOKです。

Date Box 操作時の 00:00 セット

<2017/09/22追記>
Date Box については、Date Picker からの選択時に 00:00 が自動的にセットされるので、ここから先は本来不要です。
(コメント欄参照。howdy39さんご指摘ありがとうございます。)
勝手に DateTime Picker に進化するとか、そんな将来の仕様変更を恐れる方は、適用しておくと安心でしょう。
</追記ここまで>

changeEvent1.png
changeEvent2.png

対象の Date Box を選択して、Events > onValueEdit を、プリセットアクションの Reload Datasource からカスタムアクションに変更し、上で作成した関数を load() の前で呼ぶようにします。

[CustomAction]
updateQueryDates(); //<===========insert
widget.datasource.load();

終了日指定の Date Box にも、同様のイベント調整を行ってください。

以上でOK!


(雑感)
Googleの仕組みはすべてシリコンバレー仕様。
グローバル企業なのだから UTC にしてくれればよいのに・・・
そうすればサンプルを作るGoogle社員も、こんな問題は予め気づいてくれたことでしょうに。

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2