質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google カレンダー

Google カレンダーは、Google社が提供する無料のスケジュール管理ツールです。パソコンやスマートフォン、タブレットなどからアクセスし、スケジュールの追加・変更が可能。Googleアカウントがあれば誰でも使用できます。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

受付中

Google Apps Scriptで複数人のうち誰か一人でも空いている時間を出力したい

rutsubo
rutsubo

総合スコア0

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google カレンダー

Google カレンダーは、Google社が提供する無料のスケジュール管理ツールです。パソコンやスマートフォン、タブレットなどからアクセスし、スケジュールの追加・変更が可能。Googleアカウントがあれば誰でも使用できます。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

1回答

0評価

1クリップ

424閲覧

投稿2022/05/05 02:40

下記記事をもとに、それぞれの人の空き時間と、全員が空いている時間は出力できたのですが、少なくとも誰か一人が空いている時間の出力の仕方がわからなかったため、ご教示いただきたいです

https://www.shanaidx.com/calendar_akijikan/

function main() { clear()//初期化 // シート情報取得 const sheet = SpreadsheetApp.getActiveSpreadsheet() const list = sheet.getSheetByName("入力") const list_data = list.getDataRange().getValues() const list2 = sheet.getSheetByName("結果") const list3 = sheet.getSheetByName("名簿") const list3_data = list3.getDataRange().getValues() const start_day = Utilities.formatDate(list_data[2][2] , "Asia/Tokyo", "yyyy/MM/dd 00:00:00"); // 対象開始日 const end_day = Utilities.formatDate(list_data[2][3] , "Asia/Tokyo", "yyyy/MM/dd 00:00:00"); // 対象終了日 const holiday = list_data[9][8] // 祝日 const minAssuringMinutes = sheet.getRange("G3").getValue() //確保したい時間(分) const travelTime1 = sheet.getRange("J3").getValue() //移動時間(前) const travelTime2 = sheet.getRange("K3").getValue() //移動時間(後) var wantTimes = minAssuringMinutes + travelTime1 + travelTime2 //必要な時間(分) var ok_time = []; // 空き時間 var add = []; // 対象アドレス for (var i=2, j=0; i<list_data.length; i++, j++){ if(list_data[i][1] == 1 ){ add.push(list3_data[j][2]) } } /* 全員共通の空き時間出力 */ const startdate = new Date(start_day); // 指定開始日 const enddate = new Date(end_day); // 指定終了日 var day_count = (enddate - startdate) / (1000 * 60 * 60 * 24); // 指定日数 // 一日ずつ空き時間を計算 for(var c=0;c<=day_count;c++){ var start_time = Utilities.formatDate(list_data[2][4] , "Asia/Tokyo", "HH:mm") // 指定開始時間 var end_time = Utilities.formatDate(list_data[2][5] , "Asia/Tokyo", "HH:mm") // 指定終了時間 var cal_starttime = []; // 予定開始時間 var cal_endtime = []; // 予定終了時間 // 一人ずつ予定を抽出 for(var i=0; i<add.length; i++){ var date = new Date(Date.parse(start_day) + (c * 60 * 60 * 24 * 1000)); var cal = CalendarApp.getCalendarById(add[i]); var events = cal.getEventsForDay(date) var setFlag = setFlag = holiFlag(date,holiday)//祝日の判定 if(events.length > 0 ){ if(setFlag == true){ //祝日ではないor祝日チェックなし for(var e=0; e<events.length; e++){// 取得した予定を配列に入力 if (events[e].isAllDayEvent() == false) { //終日予定は避ける var start1 = events[e].getStartTime()// 予定開始時間 var end1 = events[e].getEndTime() // 予定終了時間 cal_starttime.push(start1.getTime()) // 個人の予定開始時間を配列に追加 cal_endtime.push(end1.getTime()) // 個人の予定終了時間を配列に追加 } } } } // 指定開始・終了時間を設定 var start_time_con = start_time.substr(0,2)// 1日の指定開始時間 var opening = date.setHours(start_time_con, 0, 0, 0) var opening = date.setMinutes(start_time.substr(3,2)); var end_time_con = end_time.substr(0,2) // 1日の指定終了時間 var closing = date.setHours(end_time_con, 0, 0, 0); var closing = date.setMinutes(end_time.substr(3,2)); cal_endtime.push(date.setHours(23, 59, 59, 999)); // 1日の終了時間 cal_endtime.unshift(opening); cal_endtime.sort(); cal_starttime.push(closing); cal_starttime.unshift(date.setHours(0, 0, 0, 0)); //1日の開始時間 cal_starttime.sort(); // 開始時間と終了時間を比較して空き時間を選出  for (var i=0;i<cal_starttime.length-1;i++) { var dateString = convert2String(cal_starttime[i+1], false); var week1 = new Date(cal_starttime[i+1]) var week_add = weekAdd(week1) var weekNum = week1.getDay(); setFlag = weekFlag(weekNum,list_data) //曜日の指定と実際の曜日を判定してフラグを設定する if(setFlag == true){  if(cal_starttime[i+1] - cal_endtime[i] >= wantTimes * 60 * 1000 && cal_starttime[i+1] != cal_endtime[i]){ var startTime = cal_endtime[i] + travelTime1 * 60 * 1000 var endTime = cal_starttime[i+1] - travelTime2 * 60 * 1000 var startTimeString = convert2String(startTime) var endTimeString = convert2String(endTime) ok_time.push([dateString+'(' + week_add + ')' + Utilities.formatString("%s-%s", startTimeString, endTimeString)]) } } } } //全員共通の空き時間を出力 for (var j=3, k=0 ;k<ok_time.length;j++,k++) { list2.getRange(j,1).setValue(ok_time[k]) } } /* 個人の空き時間出力 */ // 一人ずつの予定 for(var i=0; i<add.length; i++){ var cal = CalendarApp.getCalendarById(add[i]); var address = add[i] //出力の時に使用 // 一日ずつ空き時間を計算 for(var c=0;c<=day_count;c++){ var events = cal.getEventsForDay(date) var cal_starttime = []; // 個人の予定開始時間 var cal_endtime = []; // 個人の予定終了時間 var setFlag = holiFlag(date,holiday)//祝日の判定 if(events.length > 0 ){ if(setFlag == true){ // 取得した予定を配列に入力 for(var e=0; e<events.length; e++){ if (events[e].isAllDayEvent() == false) { //終日予定は避ける var start1 = events[e].getStartTime()// 予定開始時間 var end1 = events[e].getEndTime() // 予定終了時間 cal_starttime.push(start1.getTime()) // 個人の予定開始時間を配列に追加 cal_endtime.push(end1.getTime()) // 個人の予定終了時間を配列に追加 } } } } // 指定開始・終了時間を設定 cal_endtime.unshift(opening); cal_endtime.push(date.setHours(23, 59, 59, 999)); //一日の終了時間 cal_endtime.sort(); cal_starttime.push(closing); cal_starttime.unshift(date.setHours(0, 0, 0, 0)); //一日の開始時間 cal_starttime.sort(); // 開始時間と終了時間を比較して空き時間を選出 for (var l=0;l<cal_starttime.length-1;l++) { var dateString = convert2String(cal_starttime[l+1], false); var week1 = new Date(cal_starttime[l+1]) var week_add = weekAdd(week1) var weekNum = week1.getDay(); setFlag = weekFlag(weekNum,list_data)//曜日の指定と実際の曜日を判定してフラグを設定する if(setFlag == true){  if(cal_starttime[l+1] - cal_endtime[l] >= wantTimes * 60 * 1000 && cal_starttime[l+1] != cal_endtime[l]){ var startTime = cal_endtime[l] + travelTime1 * 60 * 1000 var endTime = cal_starttime[l+1] - travelTime2 * 60 * 1000 var startTimeString = convert2String(startTime) var endTimeString = convert2String(endTime) ok_time.push([dateString+'(' + week_add + ')' + Utilities.formatString("%s-%s", startTimeString, endTimeString)]) } } } } //個人の出力処理 var empty = []; var name = nameAdd(address) ok_time.unshift(name) //アドレスを追加 for (var n=2,p=i+2,q=0;q<ok_time.length;n++,q++){ list2.getRange(n,p).setValue(ok_time[q]) } ok_time = empty //配列を空にする } } /* * 共通処理 */ //形式を変換する function convert2String(date, withTime) { if (typeof withTime === "undefined") withTime = true; //withTimeが初期値の場合、trueを入れる  var dateTime = new Date(date); //日付取得  if (!withTime) { //withTimeに何も入ってなかったら var month = dateTime.getMonth()+1; //月 + 1 var day = dateTime.getDate(); //日 return Utilities.formatString("%d/%d", month, day);  //形式を(月/日)に } else { var hours = dateTime.getHours();  //時 var minutes = padding(dateTime.getMinutes()); //分 return Utilities.formatString("%d:%s", hours, minutes); //形式を(時:分)に } } //時間の形式を00:00とする function padding(num) { return ('00' + num).slice(-2) } //曜日の表示を配列に入れる function weekAdd(week1) { const week_list = new Array('日', '月', '火', '水', '木', '金', '土');//曜日の配列 const weekNum = week1.getDay(); // 曜日を表す数値 const week = week_list[weekNum];// 曜日取得 return(week) } //曜日の指定と実際の曜日を判定してフラグを設定する function weekFlag(weekNum,list_data) { var setFlag = true for(i=1,j=0;i<9,j<7;i++,j++) if(list_data[i][8] == 0 && weekNum == j){ setFlag = false break } return setFlag } //祝日を判定してフラグを設定する function holiFlag(date,holiday){ var setFlag = true var calendarholi = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com') var holiEvents = calendarholi.getEventsForDay(date); if(holiday == 0 && holiEvents.length > 0){ setFlag = false //フラグをfalseにする } return setFlag } //名簿から名前を取得 function nameAdd(address) { const sheet = SpreadsheetApp.getActiveSpreadsheet(); const list3 = sheet.getSheetByName("名簿"); let list3_data = list3.getDataRange().getValues(); for (a in list3_data) { if(address == list3_data[a][2]) {     var fullname = (list3_data[a][0]+' '+list3_data[a][1]) } } if(fullname == ''){ fullname = address } return fullname; } /* * クリア */ //結果出力欄のクリア function clear() { const sheet = SpreadsheetApp.getActiveSpreadsheet(); const list3 = sheet.getSheetByName("結果"); var range = list3.getRange("A2:Z50"); range.clearContent(); } //入力チェック欄のクリア function clear_check() { const sheet = SpreadsheetApp.getActiveSpreadsheet(); const list = sheet.getSheetByName("入力"); var range = list.getRange("B3:B25"); range.clearContent(); } /* * バーの追加 */ function onOpen(event) { var ui = SpreadsheetApp.getUi() var menu = ui.createMenu('空き時間の算出') menu.addItem('空き時間の算出', 'main') // 空き時間算出処理 menu.addItem('結果のクリア', 'clear') // 空き時間算出処理 menu.addToUi() }

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

qnoir

2022/05/05 03:03

「それぞれの人の空き時間」が出力できているのならば、それら自体が「少なくとも誰か一人が空いている時間」に該当しています。 データとしては「それぞれの人の空き時間」を列挙すれば十分のはずです。 具体的に質問者さんは、「少なくとも誰か一人が空いている時間」をどう表現したいのでしょうか? たとえば Aさんの空き時間: 10:00~11:00 Bさんの空き時間: 10:30~12:00 Cさんの空き時間: 10:50~15:00 となっているとき、 ・「全員の空き時間」は「10:50~11:00」です。 ・一方、「少なくとも誰か一人が空いている時間」は 10:00~11:00、10:30~12:00、10:50~15:00 ということもできます。 しかし、これらを併合して、つまり「重なっている部分は除外してつなげて」 「10:00~15:00」 と変換したい、ということでしょうか?
rutsubo

2022/05/05 03:11

見ていただき、ありがとうございます。 言葉足らずで申し訳ございません、qnoir様のご認識の通りです。 背景を記載いたしますと、先方との日程調整を行うにあたり、4人のうちの誰かが対応できれば良いため、少なくとも一人が空いている日程をコピペで送ることができるように、重複を除いてスプレッドシートに出力したいと考えています。 その他ご不明点ございましたら、何なりとお申し付けください。
qnoir

2022/05/08 05:46 編集

回答しましたが、まだ不明な点があります。 各担当者の途中での交代は許容されている、という理解でよろしいのでしょうか。 というのは、たとえば、 ・Aさんの空き時間が 10:30~11:00 ・Bさんの空き時間が 11:00~11:30 ・確保したい時間が25分 ・移動時間は0 と仮定した場合、 質問者さんの先のコメントの意図通りに回答するならば 「誰か1人以上空いている時間帯」は「10:30~11:30」となります。(回答プログラムもそのようにしています) ここで、「少なくとも一人が空いている日程」を「10:30~11:30」というように案内しまって、本当に大丈夫なのでしょうか? 得られた「10:30~11:30」というのは、あくまでも「誰か1人以上空き時間となっている時間帯の集合から重なりを除外してつなげた表現」に過ぎませんので 「10:30~11:30」の範囲内であれば誰か1人が必ず対応できるというわけではありません。 途中で交代が許容されていないのであれば、たとえば「10:50~11:15」 の会議には誰も対応できません。 途中での交代が許容されていない場合、対応可能な時間帯を「10:30~11:00と11:00~11:30」として案内するというのが適切かと思います。 これは冒頭で申し上げた通り、各人の空き時間の列挙で代替できます。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google カレンダー

Google カレンダーは、Google社が提供する無料のスケジュール管理ツールです。パソコンやスマートフォン、タブレットなどからアクセスし、スケジュールの追加・変更が可能。Googleアカウントがあれば誰でも使用できます。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。