gasの覚書です。
Contents
GAS(Google Action Script)のトリガーなどの上限とスクリプトの実行時間
トリガーの上限とスクリプトの実行時間は踏まえて設計する必要がありそうです。この2つを回避する形で考えていくことになりやすいです。
この手のサービスは必ず上限があるため、先に制限を調べるのは大事です。
GASで設定できる時間指定のトリガーの上限は20らしい
— 須賀 (@sghryi) May 23, 2019
どうしようか
exception: this script has too many triggers. triggers must be deleted from the script before more can be added.
トリガーの上限が20なので、試しに21個登録したらエラーがでました。単純にトリガーの数という理解で大丈夫そうです。
エラー
Exception: This script has too many triggers. Triggers must be deleted from the script before more can be added.
setTweet
スクリプトのランタイムは6分制限です。データの読み込みに6分以上かかるとアウトです。
極力、少ない実行数にしましょう。
他の条件もGoogleさんのリファレンスに綺麗にまとまっていました。
GASの定期実行(登録・削除・取得・管理)
GASにスケジュール登録する
時計のアイコン[トリガー] > 新しいトリガーを作成します > イベントソースを選択[時間主導型]
ただ、大雑把にしか時間指定できないようです。
時間ベースのトリガーのタイプを選択を[特定日時]に変更
管理画面から手動で設定できますけど、GASでプログラムを書いて制御する方法がよさそうです。setTriggerです。
GASのトリガー特定の日時!
setTriggerを実行してみましょう。
初回、このコードを実行するために権限の許可が必要です。
function setTrigger() {
const date = new Date(2023, 4, 30, 0, 1);
ScriptApp.newTrigger('tweet').timeBased().at(date).create();
}
時計のアイコン[トリガー]を確認すると、スケジュールに登録されています。
その時間になると、newTriggerのツイートが実行される仕組みです。
登録は20個までの上限があるため、登録したら削除してあげる必要がありそうです。
GASのトリガー毎日・毎時間定期実行
毎時間実行する方法です。毎日は.everyDays(1)ですかね。
function updateSchedule() {
ScriptApp.newTrigger("scheduleTweet")
.timeBased()
.everyHours(1)
.create();
}
GASのトリガー毎時間定期実行のデメリット
よくみると、1時間おき、2時間おき、4時間おき、6時間おき、8時間おき、12時間おきしかない!
5時間おきに設定したくてもできない。プログラミングからそれ以外の設定を割り当てようとすると、勝手に1時間おきになります。このあたりは中途半端な気がしましたね。
gasのスケジュールを削除する
全トリガーを削除するコードです。
function deleteTrigger() {
const removeTriggers = ScriptApp.getProjectTriggers();
for(const removeTrigger of removeTriggers ){
ScriptApp.deleteTrigger(removeTrigger );
}
}
JavaScriptの経過日数のサンプル
タイムスタンプを 1000(ミリ秒) × 60(秒) × 60(分) × 24(時間) = 86400000 で割ると経過日数です。Math.floorは小数点切り捨て。
const startDate = new Date('2023-01-01');
const daysPassed = calculateDaysPassed(startDate);
console.log('経過日数:', daysPassed);
function calculateDaysPassed(startDate) {
const now = new Date();
const timeDifference = now.getTime() - startDate.getTime();
const daysPassed = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
return daysPassed;
}
GASのトリガー
GASでトリガーを取得するサンプル
eventオブジェクトを受け取れる。
function schedule(event) {
const triggerUid = event.triggerUid;
const trigger = ScriptApp.getProjectTriggers().find(trigger => trigger.getUniqueId() === triggerUid);
}
ただ、gasは取得できる状態が限られているようです。詳細時間が取得できないっぽいです。この点は残念で改善してもらえるとよい気もしますね。
GASでトリガーを取得してログを確認する方法
普通に実行するとこうなる!まあ、eventが入っていないので当たり前という気がする。
TypeError: Cannot read properties of undefined (reading 'triggerUid')
eventの実行ログを確認する方法はトリガーから行わないとダメなようだ。
トリガーの実行数から確認するとよいです。
トリガー > 縦3点 > 実行数
[トリガーを追加]からデバッグ用のトリガーを作るか、普通に登録して管理画面から時間調整とかでしょうか。
デバッグ用のトリガーの作り方。
トリガー > トリガーを追加
- eventを受け取る関数
- 時間主導型
- 分ベースのタイマー
- 1分おき(すぐデバッグできるように)
GASの弱点を克服するサンプルコード
GASはトリガーから詳細時間を取得できませんからスクリプトプロパティによる応用を考える気がします。。
その対策としてstackoverflowのこのコードは素晴らしい!
ARGUMENTS_KEY = "arguments"
- setする際にargumentsを識別子に使う
- setする際にオブジェクトとして格納する
- getする際にイベントオブジェクトで取得する
脱初心者向けのコードですね。個人的にも応用させてもらったのでありがとうございます。
new Date(year, month – 1, day, hour, minute);
忘れないように注意。
new Date(year, month - 1, day, hour, minute);
JavaScriptでは、Date
オブジェクトを扱う際に月は0から始まります。つまり、1月は0、2月は1、12月は11となります。
なぜJavaScriptのDateオブジェクトは月を0から数えるのですか?1月を0月と表現すると、バグを誘発しないでしょうか?
https://jp.quora.com/%E3%81%AA%E3%81%9CJavaScript%E3%81%AEDate%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%E6%9C%88%E3%82%920%E3%81%8B%E3%82%89%E6%95%B0%E3%81%88%E3%82%8B%E3%81%AE%E3%81%A7%E3%81%99%E3%81%8B-1%E6%9C%88
GASでタイムゾーンUTCで時間がずれる
次のコードでUTC(協定世界時)の概要がわかる。
const date = new Date(year, month - 1, day, hour, minute);
console.log(`Local Date: ${date}`);
const utcDate = new Date(Date.UTC(year, month - 1, day, hour, minute));
console.log(`UTC Date: ${utcDate}`);
console.log(`UTC Date: ${utcDate.toISOString()}`);
ただし、GASは内部的にはすべてUTCで日時を管理しているっぽいです。GASのみならあまり使うことないかもですね。
むしろ問題になるのは、JavaScriptのDate
オブジェクトをJSON文字列に変換すると、その日付と時刻はUTCで表されます。こうなると、混乱しやすいのでJSON.stringify()する前に文字列に変換する必要がありそうだ。
propertiesObj.triggerTime = propertiesObj.triggerTime.toString();
UTCの時間は日本時間から9時間をひいた数字。JSON.stringify()を使ったのち、スクリプトプロパティに保存ずると9時間ずれてしまいます。UTCの時間になっただけだから別にいいんだけど、デバッグする際に紛らわしいため文字列に変換した方が安心感があります。
GAS(Google Action Script)でスプレッドシートのスケジュール重複チェック
function createDateTime() {
const sheetName = "schedule";
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const lastRow = sheet.getLastRow();
const scheduledDates = []; // 実施日を格納する配列
// ... (省略) ...
for (let i = 0; i < noValues.length; i++) {
// ... (省略) ...
// 実施日を取得
const scheduledDateTime = new Date(date + ' ' + time);
// 実施日が配列内で重複しているかチェック
if (scheduledDates.includes(scheduledDateTime.toString())) {
console.log('同じ年月日時刻のスケジュールが存在するため、登録をスキップします。');
continue;
}
// 実施日を配列に追加
scheduledDates.push(scheduledDateTime.toString());
// ... (省略) ...
setScheduleTrigger(scheduledDateTime);
}
}
次のような書き方もできるが、あまりパフォーマンスがよくない。基本for文を使う方法がシンプルイズベスト。
const duplicateIndex = findDuplicateSchedule(scheduledDateTime, i, dateValues, timeValues);
if (duplicateIndex !== -1) {
console.log('同じ年月日時刻のスケジュールが存在するため、登録をスキップします。');
continue;
}
function findDuplicateSchedule(scheduledDateTime, currentIndex, dateValues, timeValues) {
for (let i = 0; i < currentIndex; i++) {
const date = dateValues[i][0];
const time = timeValues[i][0];
const dateTime = new Date(date + ' ' + time);
if (dateTime.getTime() === scheduledDateTime.getTime()) {
return i;
}
}
return -1;
}
GAS(Google Action Script)でスプレッドシートのAPI
便利だったものめもです。ハイパーリンクを設定するときに便利です。複数枚可。
setLinkUrl(startOffset, endOffset, linkUrl)
https://developers.google.com/apps-script/reference/spreadsheet/rich-text-value-builder?hl=ja#setlinkurlstartoffset-numeric,-endoffset-numeric,-url-string
newRichTextValue()
とsetRichTextValue(richTextValue):とあわせて使うとよいです。
var richText = SpreadsheetApp.newRichTextValue()
https://developers.google.com/apps-script/reference/spreadsheet/range?hl=ja#setrichtextvaluerichtextvalue
.setText(“Hello world”)
.setTextStyle(0, 5, bold)
.build();
range.setRichTextValue(richText);
ご参考になれば幸いです。
コメント