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

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

新規登録して質問してみよう
ただいま回答率
85.31%
Google Apps Script

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

Q&A

解決済

1回答

332閲覧

googleカレンダーで特定の予定を他のカレンダーにコピーしたい

KOKUBUN

総合スコア1

Google Apps Script

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

1グッド

1クリップ

投稿2025/05/20 13:30

編集2025/05/20 14:38

実現したいこと

美容室で、美容師ごとの予約共有をgoogleカレンダーで行いたいです。

大元のカレンダーには、都合上「美容師全員」の予定が入ってしまうので、
「予定の説明」部分から「美容師の名前(佐藤)」を含むものを抜き出し、
別のカレンダー(佐藤のカレンダー)にコピーしたいと思っております。

発生している問題・分からないこと

エラー内容は下記の通りです。

エラーメッセージ

error

1Exception: The parameters (String,String,String) don't match the method signature for CalendarApp.Calendar.createEvent. 2myFunction @ コード.gs:53

該当のソースコード

function myFunction() { // カレンダーID var fromCalendarID = 'xxxxxxx@group.calendar.google.com'; // 個人カレンダー(元) var toCalendarID = 'xxxxxxx@group.calendar.google.com'; // 共有カレンダー(先) // スプレッドシート:シート名 var SHEET_NAME = '佐藤'; // スプレッドシート:開始位置 var RANGE = 1; // シート情報を取得 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME); // シートを初期化 sheet.clear(); // 登録元のカレンダー情報を取得 var calendar = CalendarApp.getCalendarById(fromCalendarID); // 登録元カレンダーから翌月末日までの予定を取得 var today = new Date(); var schedules = calendar.getEvents(today, new Date(today.getFullYear(), today.getMonth() + 2, 0)); // 登録元の予定の中で「佐藤」の付いてる予定だけを出力する for(var index = 0; index < schedules.length; index++) { var range = RANGE + index; if(schedules[index].getDescription().indexOf("佐藤") != -1) { // 開始時間を出力 sheet.getRange(range, 3).setValue(schedules[index].getStartTime()); // 終了時間を出力 sheet.getRange(range, 4).setValue(schedules[index].getEndTime()); // 予定名を出力→*を削除 sheet.getRange(range, 5).setValue(schedules[index].getDescription().replace("佐藤","")); } } // 登録先のカレンダー情報を取得 var tocalendar = CalendarApp.getCalendarById(toCalendarID); // 登録先カレンダーから翌月末日までの予定を取得 var toschedules = tocalendar.getEvents(today, new Date(today.getFullYear(), today.getMonth() + 2, 0)); // 既に登録されている予定の中で「佐藤」が付いてるやつを削除 for(var i = 0; i < toschedules.length; i++) { var eventname = toschedules[i].getDescription(); if(eventname.indexOf("佐藤") != -1){ toschedules[i].deleteEvent(); } } // 予定を再登録(タイトルに★を付ける) for(var i = 1; i <= sheet.getLastRow(); i++) { var cleateTitle = "★" + sheet.getRange(i, 5).getValue(); var cleateStart = sheet.getRange(i, 3).getValue(); var cleateEnd = sheet.getRange(i, 4).getValue(); var newevent = tocalendar.createEvent(cleateTitle, cleateStart, cleateEnd); } }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

GASは、別の方が使用してOKとネットに公開しているものを一部書き換えました。元コードでは、「予定のタイトル」から「特定の文字」を含む予定を抽出してコピーするというものですが、上手くいきません。恐れ入りますが、ご教示ください。

補足

・この「全員分のカレンダー」から「美容師別」へのコピーを、名前別に10人分行いたいと考えています。
・実行されるタイミングが指定できるならば、毎日0:00にできると有難いです。

TN8001😄を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2025/05/20 13:59

JavaとJavaScriptは全く別の言語です。 「Java」タグは外してください。 「Google Apps Script」・「Google カレンダー」・「Google スプレッドシート」等のタグを付けてください。 質問はいつでも何度でも編集できます。
bebebe_

2025/05/21 00:45

var newevent = tocalendar.createEvent(cleateTitle, cleateStart, cleateEnd); の cleateStart と cleateEnd が Date型 でないといけないのに対して String型 になってしまっている気がします。 カレンダーの予定を出力しているシートの3,4列目の表示形式を日時にした場合はどうなりますか?
KOKUBUN

2025/05/21 13:41

コメントいただき、ありがとうございます。「カレンダーの予定を出力しているシートの3,4列目の表示形式を日時に」する修正について調べましたが、フォーマットの仕方がよく理解できませんでした。 不勉強でお手数をお掛けし申し訳ありませんが、どの部分をどのように直せばよいかご教示いただけますでしょうか。
bebebe_

2025/05/22 06:29 編集

確認ですが'佐藤'のシートに1行目から順にC列に開始日時 D列に終了日時 E列に説明 が出力されていますか? されていればコードの最後のところを var cleateStartValue = sheet.getRange(i, 3).getValue(); var cleateEndValue = sheet.getRange(i, 4).getValue(); // Dateオブジェクトに変換 var cleateStart = new Date(cleateStartValue); var cleateEnd = new Date(cleateEndValue); console.log(cleateStart); console.log(cleateEnd); var newevent = tocalendar.createEvent(cleateTitle, cleateStart, cleateEnd); にして実行した場合に実行ログに 「Invalid Date」と表示されるところは日時として認識できていません。
KOKUBUN

2025/05/22 13:25

丁寧に教えていただき、ありがとうございます。ご指摘いただいた点を確認したところ、1行目から予定が出力されていませんでした。私の力不足で教えていただいたことがコードに反映できなかったため、大変恐れ入りますがコードをすべて記載いただいて解決できた方のご回答をベストアンサーにさせていただきました。貴重なお時間を割いていただき、ありがとうございました。
guest

回答1

0

ベストアンサー

スプレッドシートへの出力をする際に
range(出力する行番号)を予定ごとに更新しているので、
説明に「佐藤」が含まれない予定があるとその行が空行になります。

その後、カレンダーに予定を登録する際に
その空行も対象にしているのでエラーが発生するのだと思います

回避方法としては、
例えば次のコードのように
繰返し処理の前にrange(出力する行番号)の初期値をRANGE(記入開始行)に設定しておき、
繰返し処理の中でスプレッドシートに出力する際には
説明に「佐藤」が含まれる予定の時だけrangeの更新をするようにします

JavaScript

1 // 登録元の予定の中で「佐藤」の付いてる予定だけを出力する 2 var range = RANGE; // 記入開始行 3 for (var index = 0; index < schedules.length; index++) { 4 if (schedules[index].getDescription().indexOf("佐藤") != -1) { 5 // 開始時間を出力 6 sheet.getRange(range, 3).setValue(schedules[index].getStartTime()); 7 // 終了時間を出力 8 sheet.getRange(range, 4).setValue(schedules[index].getEndTime()); 9 // 予定名を出力→*を削除 10 sheet.getRange(range, 5).setValue(schedules[index].getDescription().replace("佐藤", "")); 11 // 出力する行を更新 12 range++; 13 } 14 }

なお、
予定のスプレッドシートへの出力の際に
開始行をRANGEで指定していたのですから

JavaScript

1 // 予定を再登録(タイトルに★を付ける) 2 for (var i = 1; i <= sheet.getLastRow(); i++) {

のところは i = 1ではなく
次のように i = RANGEとしておかないと
RANGE(記入開始行)を1以外にしたときにも1行目から再登録しようとしてエラーが発生します

JavaScript

1 // 予定を再登録(タイトルに★を付ける) 2 for (var i = RANGE; i <= sheet.getLastRow(); i++) {

今回は、エラーについてのみ回答しました

【以下は、参考までに複数のメンバーの予定の転記に対応したコードの例です】

JavaScript

1// IDマスタというシートに各メンバーの名前(A列) カレンダーID(B列)を記入しておく 2// この関数を時間主導型のトリガーで深夜帯に実行するように設定しておく 3function myFunction() { 4 // このスクリプトで転記した予定につける目印 5 const eventMark = '★'; 6 7 // 転記元カレンダーID 8 const fromCalendarID = 'xxxxxxx@group.calendar.google.com'; 9 10 // メンバーの名前とカレンダーIDを記入したシート名 11 const idSheetName = 'IDマスタ'; 12 13 // メンバーのシートへの記入開始位置 14 const startRow = 1; 15 16 // スプレッドシートを取得 17 const ss = SpreadsheetApp.getActiveSpreadsheet(); 18 19 // メンバーごとの氏名とカレンダーIDをシートから取得 20 const idSheet = ss.getSheetByName(idSheetName); 21 if (!idSheet) { 22 console.log(`${idSheetName}シートが見つかりませんでした`); 23 return; 24 } 25 26 const idValues = idSheet.getDataRange().getDisplayValues(); 27 const members = idValues 28 .filter(v => v[0] && v[1]) // 空の行をフィルタリング 29 .map(v => ({ name: v[0].trim(), id: v[1].trim() })); 30 31 if (members.length === 0) { 32 console.log(`${idSheetName}シートに有効なメンバーデータがありません`); 33 return; 34 } 35 36 // 登録元カレンダーから翌月末日までの予定を取得 37 const calendar = CalendarApp.getCalendarById(fromCalendarID); 38 const today = new Date(); 39 const nextMonthEnd = new Date(today.getFullYear(), today.getMonth() + 2, 0); 40 41 const schedules = calendar.getEvents(today, nextMonthEnd) 42 .map(e => ({ 43 title: e.getTitle(), 44 start: e.getStartTime(), 45 end: e.getEndTime(), 46 description: e.getDescription() ?? '', 47 })); 48 49 console.log(`取得した予定数: ${schedules.length}`); 50 51 // メンバーごとのカレンダーオブジェクトを事前に取得・キャッシュ 52 const memberCalendars = new Map(); 53 for (const member of members) { 54 const cal = CalendarApp.getCalendarById(member.id); 55 memberCalendars.set(member.id, cal); 56 } 57 58 // バッチ処理用の配列 59 const sheetOperations = []; 60 const calendarOperations = []; 61 62 // メンバーごとに処理 63 members.forEach(member => { 64 // メンバー名と同じ名前の転記先シートを取得または作成 65 let sheet = ss.getSheetByName(member.name); 66 if (!sheet) { 67 sheet = ss.insertSheet(member.name); 68 console.log(`${member.name}というシートを作成しました`); 69 } 70 71 // 説明欄にメンバー名がある予定を抽出 72 const events = schedules.filter(e => 73 e.description.includes(member.name) 74 ); 75 76 // シート操作をバッチに追加 77 sheetOperations.push({ 78 sheet: sheet, 79 member: member, 80 events: events 81 }); 82 83 // カレンダー操作をバッチに追加 84 const memberCalendar = memberCalendars.get(member.id); 85 if (memberCalendar && events.length > 0) { 86 calendarOperations.push({ 87 calendar: memberCalendar, 88 member: member, 89 events: events 90 }); 91 } 92 93 }); 94 95 // シート操作をバッチ実行 96 console.log('シート更新を開始...'); 97 sheetOperations.forEach(op => { 98 if (op.events.length > 0) { 99 // 事前に対象範囲をクリア 100 const lastRow = op.sheet.getLastRow(); 101 if (lastRow >= startRow) { 102 op.sheet.getRange(startRow, 1, lastRow, op.sheet.getLastColumn()) 103 .clearContent(); 104 } 105 106 // データを一括書き込み 107 const values = op.events.map(e => [ 108 e.start, 109 e.end, 110 e.description.replace(new RegExp(op.member.name, 'g'), '').trim() 111 ]); 112 113 if (values.length > 0) { 114 op.sheet.getRange(startRow, 1, values.length, values[0].length) 115 .setValues(values); 116 } 117 } 118 }); 119 120 // カレンダー操作をバッチ実行 121 console.log('カレンダー更新を開始...'); 122 calendarOperations.forEach(op => { 123 // 既存の★付き予定を一括削除 124 const existingEvents = op.calendar.getEvents(today, nextMonthEnd); 125 const eventsToDelete = existingEvents.filter(e => 126 e.getTitle().startsWith(eventMark) 127 ); 128 129 // 削除を並列実行するために配列に集める 130 eventsToDelete.forEach(e => { 131 e.deleteEvent(); 132 }); 133 134 // 新しい予定を一括作成 135 op.events.forEach(e => { 136 op.calendar.createEvent(eventMark + e.title, e.start, e.end); 137 }); 138 139 }); 140 141 console.log('処理完了'); 142 143}

投稿2025/05/22 08:17

編集2025/05/27 11:03
YellowGreen

総合スコア868

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KOKUBUN

2025/05/22 13:21

正しい配列を教えていただき、ありがとうございました。他の方にもご指摘いただいていましたが、スプレッドシートに出力される予定について空白の行が入ってしまっておりましたが、自分では解決できませんでした。大変助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問