google.script.run の結果が null になるときは、Date が混じっていないかを見る
サーバーの関数でシートを読んで返したのに、画面の側には null しか届きません。 ログを見ると、値は入っています。この組み合わせのときは、まず日付を疑ってみてください。
google.script.run でサーバーとやりとりできる値には、型の決まりがあります。数値・真偽値・文字列・null と、それだけで組んだオブジェクトと配列です。Date は入っていません。
公式のガイドには、Date を渡そうとするとリクエストが失敗する、と書かれています。オブジェクトや配列の中に入っている Date も同じ扱いです。100行の表のどこか1セルに日付があるだけで、全体が届かなくなります。
失敗ハンドラではなく、成功ハンドラに null が届くことがある
公式の書き方は「失敗する(fail)」です。ところが実際には、withFailureHandler が呼ばれないことがあります。withSuccessHandler に null が届いた、という報告が Issue Tracker や Stack Overflow に上がっています。
エラーにならないので、原因に気づきにくくなります。成功ハンドラの中で null を受け取ったら、まず返した値に Date がないかを見てください。
| 見えていること | 見るところ |
|---|---|
ログには値があるのに、画面には null |
返す直前の値に Date が入っていないか |
| 日付の列を消すと届く | 日付が原因。文字にして返す |
| 一部の行だけのときに届く | その行の範囲に日付のセルがないか |
getValues() は、日付のセルを Date で返す
シートを getValues() で読むと、セルの中身に応じて数値・真偽値・Date・文字列のどれかが入ります。日付として入力されたセルは Date です。
getValues() のリファレンスには、Web アプリ向けの注意書きもあります。範囲に日付のセルがあると Web アプリへデータを返せないので、数値や文字列に変換してから返すように、という内容です。
読んだ結果をそのまま返している関数は、誰かがシートに日付の列を足しただけで、一覧が空になります。
返す前に、日付を文字にする
読んだ値を返す前に、Date だけを文字列に置き換えます。
function readRows() {
const ss = SpreadsheetApp.openById(SHEET_ID); // SHEET_ID は自分の表の ID
const tz = ss.getSpreadsheetTimeZone();
const values = ss.getSheetByName('一覧').getDataRange().getValues();
return values.map((row) =>
row.map((v) => (v instanceof Date ? Utilities.formatDate(v, tz, 'yyyy-MM-dd') : v)),
);
}
'一覧' はシートの名前に、'yyyy-MM-dd' は返したい形に置き換えてください。時刻まで要るなら 'yyyy-MM-dd HH:mm' のようにします。
getDisplayValues() を使う手もあります。セルに表示されているとおりの文字列で返ってくるので、Date は混じりません。ただ、数値も「1,200」のような表示の形で届きます。計算に使う列があるなら、上のように Date だけを置き換えるほうが扱いやすいです。
文字にするときのタイムゾーン
スクリプトとスプレッドシートは、別々にタイムゾーンを持っています。この2つが食い違うのはよくあるバグの原因だ、と公式のリファレンスにも書かれています。
上の例では ss.getSpreadsheetTimeZone() を使っています。シートに見えている日付と同じ日付を返すためです。Session.getScriptTimeZone() を使うと、スクリプト側の設定が違う場合に、日付が1日ずれて見えることがあります。
時刻まで正確にやりとりしたいなら、上の readRows() の formatDate を、UTC の ISO 8601 形式にする次の書き方に置き換えます。
const iso = Utilities.formatDate(v, 'UTC', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
画面の側では new Date(iso) で Date に戻ります。toLocaleString() などで表示すると、ブラウザのタイムゾーンで出ます。
画面からサーバーへ送るときも同じ
決まりは往復どちらにもかかります。画面の側で作った Date を引数に入れて呼ぶと、こちらも届きません。日付は文字列のまま送ります。
// 画面の側。<input type="date"> の value は "2026-10-13" のような文字列
google.script.run.saveDue(dueInput.value);
saveDue はサーバー側の関数名に、dueInput は日付の入力欄に置き換えてください。サーバーの側で Date が要るときは、受け取ってから作ります。
ほかに届かなくなるもの
- 関数
<form>以外の DOM 要素(<form>は唯一の引数としてなら渡せます。戻り値にはできません)- 自分自身を参照しているオブジェクト
配列の中の undefined は、null に変わって届きます。エラーにはなりませんが、受け取った側で undefined と比べている処理は思ったとおりに動きません。
書かなくても動く状態のコードを、下のツールで配っています。
社内wiki手順書や議事録を1か所にまとめます。契約も月額もなく、データは自分の Google ドライブの中だけに置かれます。