如何通过Google App Script访问他人主日历并实现人员配对及空闲查询?
Hey Sebastian, 我之前在Google Workspace环境下开发过类似的日程配对工具,刚好能解答你的问题。下面分两部分来说明实现方案:
一、无需订阅即可查询用户空闲状态的方法
要查询同事的空闲状态,核心是用Google Calendar API的Free/Busy查询接口,这个接口不需要预先订阅对方的日历,只要满足以下条件:
- 你们处于同一个Google Workspace域(如果是个人账号,对方需要在日历设置里允许你查看他们的空闲信息);
- 你的脚本拥有正确的API权限和OAuth2授权范围。
关键细节:
权限配置:
你的Google Apps Script需要启用Calendar API,并且授权范围至少包含https://www.googleapis.com/auth/calendar.readonly(如果还要创建会议,需要https://www.googleapis.com/auth/calendar)。在脚本编辑器里可以通过「资源」→「高级Google服务」开启Calendar API。Free/Busy查询示例:
下面是调用接口获取多个用户空闲状态的代码片段:function getFreeBusyStatus(userEmails, startTime, endTime) { // 构建查询参数 var request = { timeMin: startTime.toISOString(), timeMax: endTime.toISOString(), items: userEmails.map(email => ({ id: email })) }; // 调用Calendar API的freebusy.query方法 var response = Calendar.Freebusy.query(request); var freeBusyData = response.calendars; // 整理结果:返回每个用户的忙碌时段 let result = {}; for (let email in freeBusyData) { result[email] = freeBusyData[email].busy || []; } return result; }
二、开发自动配对并发送会议邀请的脚本
整个流程分为四个核心步骤,下面逐步说明:
1. 准备用户列表和时间范围
首先定义要配对的用户邮箱列表,以及你要查询的时间范围(比如未来一周的工作日):
const USER_LIST = ["colleague1@yourdomain.com", "colleague2@yourdomain.com", "colleague3@yourdomain.com"]; const START_DATE = new Date(); // 今天 const END_DATE = new Date(START_DATE.getTime() + 7 * 24 * 60 * 60 * 1000); // 7天后
2. 获取所有用户的空闲状态
调用上面的getFreeBusyStatus方法,拿到每个用户的忙碌时段,然后计算出他们的空闲时段:
function calculateFreeTimes(userBusyTimes, startTime, endTime) { // 初始化空闲时段为整个查询范围 let freeTimes = [{ start: startTime, end: endTime }]; // 遍历每个忙碌时段,切割空闲时段 userBusyTimes.forEach(busy => { let busyStart = new Date(busy.start); let busyEnd = new Date(busy.end); let newFreeTimes = []; freeTimes.forEach(free => { let freeStart = free.start; let freeEnd = free.end; // 忙碌时段在空闲时段之前,保留原空闲时段 if (busyEnd <= freeStart) { newFreeTimes.push(free); } // 忙碌时段在空闲时段之后,保留原空闲时段 else if (busyStart >= freeEnd) { newFreeTimes.push(free); } // 忙碌时段覆盖部分空闲时段,拆分出前后两段 else { if (freeStart < busyStart) { newFreeTimes.push({ start: freeStart, end: busyStart }); } if (busyEnd < freeEnd) { newFreeTimes.push({ start: busyEnd, end: freeEnd }); } } }); freeTimes = newFreeTimes; }); // 过滤掉短于30分钟的空闲时段(可自定义时长) return freeTimes.filter(free => (free.end - free.start) >= 30 * 60 * 1000); }
3. 配对用户并查找共同空闲时段
接下来可以写一个配对逻辑(比如随机配对,或者按特定规则配对),然后对比每对用户的空闲时段,找到交集:
function findCommonFreeTime(user1Free, user2Free) { let commonTimes = []; let i = 0, j = 0; while (i < user1Free.length && j < user2Free.length) { let u1Start = user1Free[i].start; let u1End = user1Free[i].end; let u2Start = user2Free[j].start; let u2End = user2Free[j].end; // 计算交集的开始和结束时间 let overlapStart = new Date(Math.max(u1Start.getTime(), u2Start.getTime())); let overlapEnd = new Date(Math.min(u1End.getTime(), u2End.getTime())); // 如果有有效交集(时长>=30分钟) if (overlapEnd > overlapStart && (overlapEnd - overlapStart) >= 30 * 60 * 1000) { commonTimes.push({ start: overlapStart, end: overlapEnd }); } // 移动指针:结束时间早的先推进 if (u1End <= u2End) { i++; } else { j++; } } return commonTimes; } // 示例:随机配对用户 function pairUsers(userList) { let shuffled = [...userList].sort(() => Math.random() - 0.5); let pairs = []; for (let i = 0; i < shuffled.length; i += 2) { if (i + 1 < shuffled.length) { pairs.push([shuffled[i], shuffled[i+1]]); } } return pairs; }
4. 创建并发送会议邀请
找到共同空闲时段后,就可以调用Calendar API创建会议,邀请对应的用户:
function createMeeting(attendees, startTime, endTime, title = "自动配对会议") { let event = { summary: title, start: { dateTime: startTime.toISOString(), timeZone: Session.getScriptTimeZone() }, end: { dateTime: endTime.toISOString(), timeZone: Session.getScriptTimeZone() }, attendees: attendees.map(email => ({ email: email })), sendUpdates: "all" // 发送邀请给所有参会者 }; // 创建会议 try { Calendar.Events.insert(event, "primary"); console.log(`已为${attendees.join(", ")}创建会议:${title}`); } catch (e) { console.error(`创建会议失败:${e.message}`); } }
整合所有流程
最后把这些函数整合起来,运行主函数即可:
function runMatchingAndMeeting() { // 1. 获取所有用户的忙碌状态 let busyStatus = getFreeBusyStatus(USER_LIST, START_DATE, END_DATE); // 2. 计算每个用户的空闲时段 let userFreeTimes = {}; for (let email in busyStatus) { userFreeTimes[email] = calculateFreeTimes(busyStatus[email], START_DATE, END_DATE); } // 3. 配对用户 let pairs = pairUsers(USER_LIST); // 4. 为每对用户查找共同空闲并创建会议 pairs.forEach(pair => { let [user1, user2] = pair; let commonFree = findCommonFreeTime(userFreeTimes[user1], userFreeTimes[user2]); if (commonFree.length > 0) { // 取第一个可用的共同空闲时段 let firstFree = commonFree[0]; createMeeting(pair, firstFree.start, firstFree.end); } else { console.log(`${user1}和${user2}在指定时间范围内没有共同空闲时段`); } }); }
注意事项
- 权限验证:第一次运行脚本时,需要授权访问Calendar API,确保你有足够的权限(如果是Workspace管理员,可以设置域内的日历共享权限,让所有用户默认允许域内成员查看空闲状态);
- 时间时区:脚本中使用
Session.getScriptTimeZone()获取时区,确保和用户的日历时区一致; - 错误处理:可以根据需要添加更多错误处理逻辑,比如处理API调用失败、用户邮箱无效等情况。
内容的提问来源于stack exchange,提问作者Sebastian
相关产品推荐
相关产品推荐

