文系でも分かる、GASによる授業通知のLINE bot の作成 その③

<a href="https://qiita.com/Ko001/items/27dcc474d7827e7cd9cb">文系でも分かる、GASによる授業通知のLINE bot の作成 その②</a>の続きです。

1. <a href="https://qiita.com/Ko001/items/9a6f9ec967f6e16171bb">文系でも分かる、GASによる授業通知のLINE bot の作成 その① 〜GASを使ったLINE botの作成〜</a>
2. <a href="https://qiita.com/Ko001/items/27dcc474d7827e7cd9cb">文系でも分かる、GASによる授業通知のLINE bot の作成 その② 〜GASとスプレッドシートの連携、日付のフォーマット〜</a>
3. 文系でも分かる、GASによる授業通知のLINE bot の作成 その③　←今回
4. <a href="https://qiita.com/Ko001/items/d35a74e3be452198b8f2">文系でも分かる、GASによる授業通知のLINE bot の作成 その④　〜setTriggerを使って、指定の時間にプッシュ通知を送る〜</a> 

#この記事でわかること
* 日付の取得の仕方
* スプレッドシートで取得した時間の計算方法

#今回やること
* 要件③ 「次」と入力すると、1番近い授業の情報を返してくれる機能を追加
![Screen Shot 2020-11-19 at 22.11.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772803/7bdbafec-a6ab-7dd7-30d8-10ecfd5381b0.png)


#流れ（要件定義）
* 「次」を含むメッセージが入力されると、
*  今の日時を取得して
*  次の授業の情報を返信する

#次の授業を取得する関数の作成

```GAS:Code.gs
function findNextClass() {
  //今の日時を取得
  var today = new Date();
　//今の時間を取得
  var hour = today.getHours();
　//今の分を取得
  var minutes = today.getMinutes();
  console.log(today);
  for(let i=0; i <= 6; i++) {
　　//今日の曜日から初めて、曜日を一つずつずらしていく
    var day = (today.getDay() + i) % 7;
    var dateColumn = day + 3;
    var array = ['日','月','火','水','木', '金', '土'];
　　//何曜日を検索しているかコンソールに表示（デバッグ用）
    console.log("曜日：" + array[day]);
    
    var searchHour = 0;
　　//もし、検索する曜日が今の曜日と一致しているなら今の時間から、そうじゃないなら朝6時から検索
    if(day == today.getDay()){searchHour = hour;} else { searchHour = 6;}
　　//検索時間が24時になるまで、１時間ずつ足して計算する
    for(var j=0; j < 24-searchHour; j++) {
      console.log(searchHour + "時");
      for(let k=2; k <= 26; k+=4){
        var classNumRow = k;
        var startTimeRow = k + 1;  
        //始業時間が設定されている場合、始業時間を取得
        if(sheet.getRange(startTimeRow, 1).getValue()) {
          var startTime = sheet.getRange(startTimeRow, 1).getValue();
          var startHour = startTime.getHours();
          var startMinutes = startTime.getMinutes();
          console.log("start hour: " + startHour);
          //検索した時、今と検索時間の日付と時間が一致していても、今の分が始業の分を超えている場合は情報を取得しない          
          if(searchHour === startHour && today.getDay() === day && hour === searchHour && minutes > startMinutes){
            console.log("\nalready orver\n");
            //時間が一致し、授業が存在する場合、情報を取得
          } else if(searchHour === startHour && sheet.getRange(classNumRow, dateColumn).getValue()){
            var classInfos = getClassInfo(classNumRow, dateColumn);
            return classInfos;
          }
        }
      }
　　　　//検索時間を１時間足す
      searchHour += 1;
    }
  }  
}

function getClassInfo(){
  //②で作ったもの
}
```
解説
今の時間に１時間ずつ足していく形で検索していきます。分は無視してXX時YY分のXXが始業時間と一致した時にその授業の情報を返します。
ただし、これだと 今が10:35で始業が同じ曜日の10:30の場合などに授業の情報を取得してしまうので、```if(searchHour === startHour && today.getDay() === day && hour === searchHour && minutes > startMinutes)``` を使っています。
一つ前の記事で書いたように、スプレッドシートに記入した時刻は変な日付が設定されてしまうため、時間と分をバラバラに扱うことで、日付を無視できるようにしています。

# ```function findNextClass``` を  ```function doPost(e)```で動くようにする
今回までの完成形のコードになります。

```GAS:Code.gs
var access_token = "自分のアクセストークン"
// 自分のユーザーIDを指定します。LINE Developersの「Your user ID」の部分です。
var user_id = "ユーザーID"

//★★スプレッドシートID★★
var ss = SpreadsheetApp.openById("スプレッドシートID");
//★★シート名★★
var sheet = ss.getSheetByName("シート名");

function doPost(e) {
  var event = JSON.parse(e.postData.contents).events[0];
  var returnMessage = "曜日と時限（半角：1〜7)を指定してね！\n次の授業が知りたいときは、「次」と入力してね！";
  if(event.source.userId == user_id){
    //返信するためのトークン取得
    var reply_token= event.replyToken;
    if (typeof reply_token === 'undefined') {
      return;
    }
    var message = event.message.text;
    for(let i=3; i<=7; i ++) {
      var dateColumn = i;
      var day = sheet.getRange(1, i).getValue();
      if(message.includes(day)){
        for(let j=2; j<=26; j += 4) {
          var classNumRow = j;
          var classNum = sheet.getRange(j, 1).getValue();
          if(message.includes(classNum) && sheet.getRange(classNumRow, dateColumn).getValue()){
            var classInfos = getClassInfo(classNumRow, dateColumn);
            var returnMessage = classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime + 
              ")\n授業名：" + classInfos.className + 
                "\nZoomID: " + classInfos.zoomID + 
                  "\nPass: " + classInfos.zoomPass;
            reply(reply_token, returnMessage);
          } else if(message.includes(classNum) && !sheet.getRange(classNumRow, dateColumn).getValue()) {
            var returnMessage = "授業はありません。"
            reply(reply_token, returnMessage);
          }
        }
      }
    }
    
    if(message.includes("次")){
      var classInfos = findNextClass();
      var returnMessage = classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime + 
        ")\n授業名：" + classInfos.className + 
          "\nZoomID: " + classInfos.zoomID + 
            "\nPass: " + classInfos.zoomPass;
      reply(reply_token, returnMessage);
    } else {reply(reply_token, returnMessage);}
  }
}

function reply(reply_token, returnMessage) {
  var reply_url = 'https://api.line.me/v2/bot/message/reply';

  // メッセージを返信 
  UrlFetchApp.fetch(reply_url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + access_token,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': returnMessage,
      }],
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

function findNextClass() {
  var today = new Date();
  var hour = today.getHours();
  var minutes = today.getMinutes();
  console.log(today);
  for(let i=0; i <= 6; i++) {
    var day = (today.getDay() + i) % 7;
    var dateColumn = day + 3;
    var array = ['日','月','火','水','木', '金', '土'];
    console.log("曜日：" + array[day]);
    
    var searchHour = 0;
    if(day == today.getDay()){searchHour = hour;} else { searchHour = 6;}
    for(var j=0; j < 24-searchHour; j++) {
      console.log(searchHour + "時");
      for(let k=2; k <= 26; k+=4){
        var classNumRow = k;
        var startTimeRow = k + 1;  
        //始業時間が設定されている場合、始業時間を取得
        if(sheet.getRange(startTimeRow, 1).getValue()) {
          var startTime = sheet.getRange(startTimeRow, 1).getValue();
          var startHour = startTime.getHours();
          var startMinutes = startTime.getMinutes();
          console.log("start hour: " + startHour);
          //検索した時、今と検索時間の日付と時間が一致していても、今の分が始業の分を超えている場合は情報を取得しない          
          if(searchHour === startHour && today.getDay() === day && hour === searchHour && minutes > startMinutes){
            console.log("\nalready orver\n");
            //時間が一致し、授業が存在する場合、情報を取得
          } else if(searchHour === startHour && sheet.getRange(classNumRow, dateColumn).getValue()){
            var classInfos = getClassInfo(classNumRow, dateColumn);
            return classInfos;
          }
        }
      }
      searchHour += 1;
    }
  }  
}

function getClassInfo(rowNum, dateColumn){
  var className = sheet.getRange(rowNum, dateColumn).getValue();
  var classDay = sheet.getRange(1, dateColumn).getValue();
  var classNum = sheet.getRange(rowNum, 1).getValue();
  var startTime = Utilities.formatDate( sheet.getRange(rowNum + 1, 1).getValue(), 'Asia/Tokyo', 'HH:mm');
  var endTime = Utilities.formatDate( sheet.getRange(rowNum + 3, 1).getValue(), 'Asia/Tokyo', 'HH:mm');
  var zoomID = sheet.getRange(rowNum + 1, dateColumn).getValue();
  var zoomPass = sheet.getRange(rowNum + 2, dateColumn).getValue();
  var classInfos = {className: className, classDay: classDay, classNum: classNum, startTime: startTime, endTime: endTime, zoomID: zoomID, zoomPass: zoomPass};
  return classInfos;
}
```

ここまでできたら、また更新して、「次」とメッセージを送って正しく動くか確かめてみましょう。

次の記事↓
<a href="https://qiita.com/Ko001/items/d35a74e3be452198b8f2">文系でも分かる、GASによる授業通知のLINE bot の作成 その④　〜setTriggerを使って、指定の時間にプッシュ通知を送る〜</a>