TypeScriptでGoogle Calendarの終日イベントをカレンダーに追加するURLを実装する方法
TypeScriptでGoogle Calendarに終日イベントを正しく追加するURLの実装方法を解説。終日イベントと時間指定イベントの違いに注目し、日付フォーマットや終了日の設定における重要なポイントを紹介します。
目次
Google Calendar に予定を追加する際、「時間指定のイベント」と「終日イベント」では扱いが大きく異なります。特にプログラムから Google Calendar に予定を追加する場合、正しい形式で登録しないと意図した通りに表示されないことがあります。
この記事では、TypeScript で Google Calendar の終日イベントを正しく登録するURLを発行するための実装方法について解説します。
Google Calendar API で終日イベントを登録する際の注意点
Google Calendar API のドキュメントを読むと、終日イベントとそれ以外では設定するパラメーターが異なることがわかります。まず、終日イベントを作成するには、start
と end
プロパティにそれぞれ date
フィールドを使用する必要があります。時刻を含む dateTime
ではありません。次に、終了日は翌日を指定する必要があります。1日のイベントなら開始日+1日という計算になります。
2番目の「終了日は翌日になる」という点は慣れるまでハマりどころになりそうです。例えば、5月1日の1日だけの終日イベントを作成する場合、開始日は「2024-05-01」、終了日は「2024-05-02」と指定する必要があります。
実装方法
では実際に、TypeScript で Google Calendar の終日イベントを正しく登録するための実装方法を見ていきましょう。
終日イベントを識別するフラグを追加
まず、イベントデータに終日イベントかどうかを示すフラグを追加します。
export function mapDetailToGoogleUrlDto(detail: CalendarEventDetail) {
const start = detail.startDate || detail.startTime || '';
const isAllDay = !!detail.startDate; // 終日イベントかどうかのフラグ
const end = detail.startDate
? dayjs(detail.startDate).add(1, 'day').format('YYYY-MM-DD') // 終日イベントの場合は+1日
: detail.startTime ? dayjs(detail.startTime).add(1.5, 'hours').toISOString() : '';
return {
title: detail.displayName,
start: start,
end: end,
location: '',
description: `${detail.displayName || ''}${detail.isSelfTraining ? '(自主練)' : ''}`,
isAllDay: isAllDay // 終日イベントフラグを追加
};
}
この例では、startDate
が設定されている場合は終日イベント、startTime
が設定されている場合は時間指定イベントと判断しています。終日イベントの場合は、終了日を開始日の翌日に設定しています。
Google Calendar に登録する URL 生成メソッドを修正
次に、Google Calendar へ予定を登録する URL を生成するメソッドを修正します。終日イベントと時間指定イベントで日付フォーマットを変える必要があるからです。
public buildGoogleCalendarParams(event: {
title: string;
start: string;
end: string;
location: string;
description: string;
isAllDay?: boolean;
}): URLSearchParams {
// 終日イベントの場合の日付フォーマット
const formatDates = () => {
if (event.isAllDay) {
// 終日イベントの場合はYYYYMMDDの形式(時間なし)
return `${dayjs(event.start).format('YYYYMMDD')}/${dayjs(event.end).format('YYYYMMDD')}`;
} else {
// 通常イベントの場合は時間も含める
return `${dayjs(event.start).format('YYYYMMDDTHHmmss')}/${dayjs(event.end).format('YYYYMMDDTHHmmss')}`;
}
};
return new URLSearchParams({
action: 'TEMPLATE',
text: event.title,
dates: formatDates(),
location: event.location,
details: event.description,
ctz: 'Asia/Tokyo',
});
}
ここでのポイントは、終日イベントの場合は YYYYMMDD
形式、時間指定イベントの場合は YYYYMMDDTHHmmss
形式を使用することです。この違いを無視すると、終日イベントが正しく表示されません。
イベント変換処理の更新
複数のイベントを処理する関数も、終日フラグに対応するように更新する必要があります。
toGoogleCalendarUrl(events: CalendarEvent[]): {
events: Array<{
title: string;
start: string;
end: string;
location: string;
description: string;
url: string;
isAllDay?: boolean;
}>;
} {
const convertedEvents = events.flatMap((calendarData) =>
calendarData.events
.map((event) => {
const start = event.startDate || event.startTime;
if (!start) return null;
const isAllDay = !!event.startDate;
return {
title: `${event.displayName}${event.isSelfTraining ? '\n(自主練)' : ''}`,
start: start,
end: event.startDate
? dayjs(event.startDate).add(1, 'day').format('YYYY-MM-DD')
: dayjs(event.startTime).add(1.5, 'hours').toISOString(),
location: this.location,
description: `${event.displayName}${event.isSelfTraining ? '\n(自主練)' : ''}`,
isAllDay: isAllDay
};
})
.filter((event): event is NonNullable<typeof event> => event !== null)
.map((event) => {
const params = this.buildGoogleCalendarParams(event);
return {
...event,
url: `https://www.google.com/calendar/render?${params}`
};
})
);
return {
events: convertedEvents
};
}
この関数では、各イベントが終日イベントかどうかを判断し、それに応じて終了日と日付フォーマットを設定しています。
予定の種類によって、日付フォーマットが異なる
日付フォーマットについても注意が必要で、終日イベントと時間指定イベントで異なることも要注意ポイントです。終日イベントでは YYYYMMDD
、時間指定イベントでは YYYYMMDDTHHmmss
を使用します。
まとめ
Google Calendar に正しく終日イベントを登録するには、終日イベントと時間指定イベントの違いを理解し、適切な日付フォーマットを使用することが重要です。今回の実装では、isAllDay
フラグを導入して日付フォーマットを動的に切り替えることで、終日イベントが正しく表示されるようになりました。
この方法を使えば、ユーザーが Google Calendar に予定を追加する際に、終日イベントとして正しく表示されるようになります。サーバーレスアプリケーションや React フロントエンドから予定登録機能を実装する際にも、同じ原則が適用できるはずです。
最近のプロジェクトでは、この実装方法を使って Cloudflare Workers と React で構築したイベント管理システムと Google Calendar を連携させ、スムーズに運用できています。皆さんのプロジェクトでも、この記事が参考になれば幸いです。