【GAS】日付・時刻のズレは必ず解決できます!原因の特定方法を解説(スプレッドシート)

2023/07/03に公開

日付や時刻が期待通りにならない、数時間ズレてる...、前日が表示される...。GASを実装してスプレッドシートを使用していると、こうした問題に遭遇することがあります。しかし、心配は無用です!この問題は必ず解決できます。
この記事では、日付・時刻のズレの原因を特定し、それを解決する方法を解説します。

日付・時刻のズレが発生する理由

日時が合わない、日付・時刻がズレてしまう主な原因は2つあります。

  • タイムゾーンの設定の問題
  • 日時データを扱う際の変換や計算が適切でない。(実装ミス)

現状の確認

タイムゾーンの設定は、スクリプトエディタとスプレッドシートの2つがあります。
タイムゾーンを確認するコードは以下の通りです。

function checkTimezone() {
  const date = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss");
  console.log("現在の日時: " + date);

  // スプレッドシートのタイムゾーンを確認
  const ss = SpreadsheetApp.getActiveSpreadsheet()
  const spreadsheetTimezone = ss.getSpreadsheetTimeZone();
  const userLocale = ss.getSpreadsheetLocale();
  console.log("スプレッドシートのタイムゾーン: " + spreadsheetTimezone);
  console.log("スプレッドシートの言語設定: " + userLocale);

  // スクリプト(GAS)のタイムゾーンを確認
  const scriptTimeZone = Session.getScriptTimeZone();
  console.log("スクリプト(GAS)のタイムゾーン: " + scriptTimeZone);

}

正しく日本時間が反映される場合は以下のようになります。

現在の日時: 2023/07/03 14:40:23
スプレッドシートのタイムゾーン: Asia/Tokyo
スプレッドシートの言語設定: ja_JP
スクリプト(GAS)のタイムゾーン: Asia/Tokyo

スプレッドシートのタイムゾーンの変更方法

スプレッドシートのメニューバーから[ファイル]→[設定]の順でクリックする。

[言語と地域]を日本、タイムゾーンを(GMT+09:00)Tokyoにする。

コードの実行で変更する場合は以下のようになります。

  const ss = SpreadsheetApp.getActiveSpreadsheet()
  ss.setSpreadsheetTimeZone("Asia/Tokyo");
  ss.setSpreadsheetLocale("ja_JP");

スクリプトエディタ(GAS)のタイムゾーンを変更する

スクリプトエディタを開き、画面左にある[プロジェクトの設定]をクリックする。

タイムゾーンの設定を(GMT+09:00) 日本標準時 – 東京にする。

タイムゾーンが日本以外になるのはどんなときですか?

Googleドライブから新しくスプレッドシートを作成した場合、タイムゾーンは日本時間になっています。日本時間以外になるのは以下のような場合です。

1. Googleフォームと連携したスプレッドシートのタイムゾーンはDili

Googleフォームの回答は自動的にスプレッドシートに反映させることができます。
この時、フォームの管理画面からスプレッドシートを作成すると、タイムゾーンは東ティモールのディリ(Dili)になります。

2. GASで作成したスプレッドシート

以下のようなコードで、新しくスプレッドシートを作成できます。

  const ssNew = SpreadsheetApp.create("新しいスプレッドシート");
  console.log(ssNew.getUrl());

GASで作成したスプレッドシートはアメリカ時間で設定されています。(未設定・空欄になる場合など様々あります。)

3. その他

GoogleドライブのExcelファイルからスプレッドシートに自動変換した場合や、Googleアカウントの地域・言語、タイムゾーンが日本以外になっている場合も要注意です。

時刻が37分ズレる問題の答え

前述したようにGoogleフォームの管理画面からスプレッドシートを作成するとタイムゾーンはDiliになります。日本と同じ協定世界時間の+9時間(GMT+09:00)の地域なので大丈夫そうに思いますが...。

検証

スプレッドシートのタイムゾーンをDiliのままにして、セルに日付と時刻を入力します。

このセルをgetValueで取得してconsole.logで出力してみると以下のようになります。

Mon Jul 03 2023 00:00:00 GMT+0900 (Japan Standard Time)
Sat Dec 30 1899 00:37:40 GMT+0900 (Japan Standard Time) 

日付を正しいですが時刻が37分40秒でズレてるのがわかります。
スクリプトエディタのタイムゾーンをDiliに変えて実行してみます。

Mon Jul 03 2023 00:00:00 GMT+0900 (East Timor Time)
Sat Dec 30 1899 00:00:00 GMT+0822 (East Timor Time) 

時刻が正しく00時00分で取得できました。ただよく見るとGMT+0822になってます。正しいGMTは+0900なので約37分ズレてます。これが原因で、セルから時刻を取得したときやUtilities.formatDateを使ってEast Timor TimeからJapan Standard Timeに時刻を変換したときにズレが発生します。

タイムゾーンを韓国・ソウル(seoul)にして試したところ同様の事象になりました。結論としては恐らくスプレッドシート(GAS)のバグだと思います。ズレを防ぐにはスクリプトエディタとスプレッドシートの2つのタイムゾーンを揃えるのがとても重要です。

時刻データの変換や計算ミス、実装コードの誤り

タイムゾーンは正しいのにそれでも日時がズレる場合があります。実装したコードに原因がある可能性が高いです。原因としてよくある3つの例を紹介します。

1. ChatGPTで生成したコードをコピペしてないですか?

現在の日時は以下のようなコードで出力できます。

  const date = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss");

Utilities.formatDateのタイムゾーンをAsia/Tokyoに指定しているので正しい日時が出力されます。ChatGPTにコードを生成してもらうと、このタイムゾーンがGMTになってる場合があります。正しいタイムゾーンを指定しましょう。

2. Dateオブジェクトは月が0~11で表される

1月は0、12月は11になります。

  const date1 = new Date();
  console.log(Utilities.formatDate(date1, "JST", "yyyy/MM/dd"));
  //2023/07/03

  const month = date1.getMonth();
  console.log("Month: " + month);
  //Month: 6
  
  const date2 = new Date(2023, 1, 15); //2月は1
  console.log(Utilities.formatDate(date2, "JST", "yyyy/MM/dd"));
  //2023/02/15
  

getMonth()やsetMonth()の処理をするときは注意しましょう。

1月31日の1ヶ月後は何月何日ですか?

各月の日数はバラバラです。以下のコードのように1月31日から月を+1して処理しようとすると、2月31日は存在しないので、2月28日から3日後の3月3日になります。

  const date1 = new Date(2023, 0, 31); //1月31日
  date1.setMonth(date1.getMonth() + 1);
  console.log(Utilities.formatDate(date1, "JST", "yyyy/MM/dd"));
  // 2023/03/03

  const date2 = new Date(2023, 1, 28); //2月28日
  date2.setDate(date2.getDate() + 3);
  console.log(Utilities.formatDate(date2, "JST", "yyyy/MM/dd"));
  // 2023/03/03

setDate()で1日にしてから、月を+1するなどして対処できます。

解決できません、助けてください!

コメント欄に現状をご記入ください。サポートいたします。

Discussion