@take0509

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【GAS】時間表記が9:00で固定されている問題を解決したい

Q&A

解決したいこと

Googleフォームを利用して休暇申請を上長・社長の承認を2段階で取るシステムを作成しています。

①Googleフォームで内容を送信

②入力内容が上長にメールで届く[sendMessage1(e)起動]
※メールで送るメッセージをプレーンでもHTMLでも送れるよう[generateBodies1(values)]を使用

③上長がメール内の「承認」ボタンを押すと、回答集計スプレッドシートの状況列が"二次確認中"に書き換えられる+承認者に承認内容のWebページが表示[doGet(e)起動]

④時間トリガーで回答集計スプレッドシートの状況列が「二次確認中」の場合に社長にメールを送信[sendMessage2()起動]

⑤社長がメール内の「承認」ボタンを押すと、回答集計スプレッドシートの状況列が"承諾"に書き換えられる+承認者に承認内容のWebページが表示+申請者に承認メール送信[doGet(e)起動]

以下の【発生している問題・エラーメッセージ】は、休暇種類項目「特別休暇」・期間項目「2023/05/17」・時間「11:00」でフォーム回答した場合に、Webページで表示される内容になります。
時間に関して、どの時間を入力してもフローの③以降9:00しか表示されません。

発生している問題・エラー

休暇申請の承認
あなたは以下の休暇申請を承認しました

休暇種類: 特別休暇
期間: 2023-05-17
時間: 9:00
備考:

該当するソースコード

function sendMessage1(e) {

  const row = e.range.getRow();
  const sheet = e.range.getSheet();
  sheet.getRange(row, 7).setValue('一次確認中');
  const bodies = generateBodies1(e.values);
  let url = 'https://~exec'; //公開したウェブアプリケーションのURL
  url += `?row=${row}&answer=`;

  const recipient = '~@アドレス'; //承認者メールアドレス        
  const subject = '休暇申請のお知らせ';
  let body = '';
  body += '以下の内容で休暇申請がありました。\n\n';
  body += bodies.plain;
  body += '承認する場合は、以下URLをクリックしてください\n';
  body += url + 'ok';
  body += '否認する場合は、以下URLをクリックしてください\n';
  body += url + 'ng';

  let html = '';
  html += '<h1>休暇申請のお知らせ</h1>';
  html += '<p>以下の内容で休暇申請がありました。</p>';
  html += bodies.html;
  html += `<p>承認する場合は、<a href="${url}ok">[承認]</a>をクリックしてください</p>`;
  html += `<p>否認する場合は、<a href="${url}ng">[否認]</a>をクリックしてください</p>`;

  GmailApp.sendEmail(recipient, subject, body, { htmlBody: html });

}
 

function generateBodies1(values) {
  const [timeStamp, email, kinds, day, time, memo] = values;

  const dayDate = new Date(day);
  const todayStr = Utilities.formatDate(dayDate, 'Asia/Tokyo', 'yyyy-MM-dd');

  const timeDate = new Date(day + " " + time);
  const totimeStr = Utilities.formatDate(timeDate, 'Asia/Tokyo', "H:mm");

  let plain = '';
  plain += `・休暇種類: ${kinds}\n`;
  plain += `・期間: ${todayStr}\n`;
  plain += `・時間: ${totimeStr} \n`;
  plain += `・備考: ${memo}\n`;
  let html = '<ul>';
  html += `<li>休暇種類: ${kinds}</li>`;
  html += `<li>期間: ${todayStr}</li>`;
  html += `<li>時間: ${totimeStr}</li>`;
  html += `<li>備考: ${memo}</li>`;
  html += '</ul>';
  return {
    email: email,
    plain: plain,
    html: html
  };
}


function doGet(e) {
  const row = e.parameter.row;
  const sheet = SpreadsheetApp.getActiveSheet();
  const values = sheet.getRange(row, 1, 1, 6).getValues()[0];
  const bodies = generateBodies1(values);
  const answer = e.parameter.answer;
  const result = {
    ok: '承認',
    ng: '否認'
  };

   var situation = sheet.getRange(row, 7).getValue();

  if (result[answer] === '承認') {

    if (situation === '一次確認中') {  //1回目の場合

      sheet.getRange(row, 7).setValue("二次確認中");

      html = '';
      html += `<h1>休暇申請の${result[answer]}</h1>`;
      html += `<p>あなたは以下の休暇申請を${result[answer]}しました</p>`;
      html += bodies.html;
      return HtmlService.createHtmlOutput(html);

    } else {
      sheet.getRange(row, 7).setValue("承認");

      const recipient = bodies.email;
      const subject = `休暇申請${result[answer]}のお知らせ`;
      let body = '';
      body += `以下の休暇申請が${result[answer]}されました。\n\n`;
      body += bodies.plain;

      let html = '';
      html += `<h1>休暇申請${result[answer]}のお知らせ</h1>`;
      html += `<p>以下の休暇申請が${result[answer]}されました。</p>`;
      html += bodies.html;

      GmailApp.sendEmail(recipient, subject, body, { htmlBody: html });

      html = '';
      html += `<h1>休暇申請の${result[answer]}</h1>`;
      html += `<p>あなたは以下の休暇申請を${result[answer]}しました</p>`;
      html += bodies.html;
      return HtmlService.createHtmlOutput(html);
    }
  } else if (result[answer] === '否認') {

    sheet.getRange(row, 7).setValue("否認");

    const recipient = bodies.email;
    const subject = `休暇申請${result[answer]}のお知らせ`;
    let body = '';
    body += `以下の休暇申請が${result[answer]}されました。\n\n`;
    body += bodies.plain;

    let html = '';
    html += `<h1>休暇申請${result[answer]}のお知らせ</h1>`;
    html += `<p>以下の休暇申請が${result[answer]}されました。</p>`;
    html += bodies.html;

    GmailApp.sendEmail(recipient, subject, body, { htmlBody: html });


    html = '';
    html += `<h1>休暇申請${result[answer]}</h1>`;
    html += `<p>あなたは以下の休暇申請を${result[answer]}しました</p>`;
    html += bodies.html;
    return HtmlService.createHtmlOutput(html);
  }
}


function sendMessage2() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('フォームの回答 1'); //「確認用」シートを取得
  var lastRow = sheet.getRange(1, 1).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow(); //「工事名称」列の最終行を取得  //https://tinyurl.com/27kh998w

  for (var i = 1; i <= lastRow; i++) { //17行目から工事名称が入っている最終行まで繰り返し

    const row = i;

    const values = sheet.getRange(row, 1, 1, 6).getValues()[0];

    const bodies1 = generateBodies1(values);

    let url = 'https://~/exec'; //公開したウェブアプリケーションのURL
    url += `?row=${row}&answer=`;

    const recipient = '~@gmail'; //承認者メールアドレス        
    const subject = '休暇申請のお知らせ';

    var val = sheet.getRange(row, 7).getValue()//「状況」セル取得

    if (val === "二次確認中") {/* 「一次確認中」なら何もしない */;

      let body = '';
      body += '以下の休暇申請がありました。\n\n';
      body += bodies1.plain;
      + "\n\n"
      body += '承認する場合は、以下URLをクリックしてください\n';
      body += url + 'ok';
      body += '否認する場合は、以下URLをクリックしてください\n';
      body += url + 'ng';

      let html = '';
      html += '<h1>休暇申請のお知らせ</h1>';
      html += '<p>以下の休暇申請がありました。</p>';
      html += bodies1.html;
      + "\n\n"
      html += `<p>承認する場合は、<a href="${url}ok">[承認]</a>をクリックしてください</p>`;
      html += `<p>否認する場合は、<a href="${url}ng">[否認]</a>をクリックしてください</p>`;

      GmailApp.sendEmail(recipient, subject, body, { htmlBody: html });

    } else {/* 「二次承認」なら何もしない */;
      ;

    }
  }
}

### 自分で試したこと
タイムゾーンが「日本標準時」であることを確認しました


0 likes

3Answer

sheet.getRange().getValues()で取得した値は、文字列ではなくすでにDateオブジェクトになっているはずです。
なので、timeDateを作らなくてもそのままtimeformatDateに渡せばいいです。

1Like

Comments

  1. @take0509

    Questioner

    ご回答ありがとうございます。
    timeDateを除いてみたのですが、
    「The parameters (String,String,String) don't match the method signature for Utilities.formatDate.」
    のエラーが出てしまいました。
    こちら変更の方法が誤っていたら申し訳ございません。

generateBodies1(values)関数で時間を処理する際、新しいDateオブジェクトを生成することで問題が発生しているかもですね。下記の様にしたらどうでしょうか?

const timeDate = new Date(`1970-01-01T${time}:00`);
const totimeStr = Utilities.formatDate(timeDate, 'Asia/Tokyo', "H:mm");
0Like

Comments

  1. @take0509

    Questioner

    ご回答ありがとうございます。
    ご教示いただいた内容で修正したのですが、変わらず9:00と記載されてしまうため再度要因を確認してみます。

  2. なるほど...別のアプローチを試して見ますか。
    ここのコードを追加して見たらどうですか?

    const [timeStamp, email, kinds, day, _time, memo] = values;
    const time = _time.split(':').map(Number);
    const timeDate = new Date(1970, 0, 1, time[0], time[1]);
    

    その後下記でフォーマットされた時間の取得ができます。

    const totimeStr = Utilities.formatDate(timeDate, 'Asia/Tokyo', "H:mm");
    
  3. @take0509

    Questioner

    再度ありがとうございます。
    ご記載いただいたコードを追加したのですが、「 _time.split is not a function」のエラーが出てしまいました。
    こちら追加の方法が誤っていたら申し訳ございません。

  4. なるほど、下記の修正してみてください。これでどうでしょうか?

    const [timeStamp, email, kinds, day, _time, memo] = values;
    const time = _time.toString().split(':').map(Number);
    const timeDate = new Date(1970, 0, 1, time[0], time[1]);
    
  5. @take0509

    Questioner

    ありがとうございます。
    unction doGet(e) 関数、function sendMessage2() 関数に原因があったようで、そちらを修正することで解決できました。
    この度はご回答ありがとうございました。

こちらfunction doGet(e) 関数、
function sendMessage2() 関数
で時間の取得が正しくできていなかったようなので、

それぞれconst values = sheet.getRange(row, 1, 1, 6).getValues()[0];getValues()[0]
getDisplayValues().flat();に変更することで解決することができました。

0Like

Your answer might help someone💌