ICSファイルとは
ICSファイル(iCalendar形式 / .ics)は、カレンダーイベントを記述する標準フォーマットです。RFC 5545で定義されており、Googleカレンダー、Outlook、Apple Calendar、Yahooカレンダーなどほぼすべてのカレンダーアプリで読み込めます。
主な用途
- イベント告知用の「カレンダーに追加」ボタン
- 会議通知メールの添付ファイル
- カレンダーの定期購読(URL購読型ICS)
- カレンダーアプリ間のデータ移行
- 予約システムからカレンダーへの自動登録
ICSファイルの基本構造
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ハカドルツールズ//ICS Generator//JA
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:20260429T120000Z
DTSTART:20260501T100000Z
DTEND:20260501T110000Z
SUMMARY:キックオフミーティング
DESCRIPTION:プロジェクトキックオフ\nZoomリンク: https://zoom.us/...
LOCATION:オンライン
END:VEVENT
END:VCALENDAR
必須プロパティ
| プロパティ | 内容 | 例 |
|---|---|---|
BEGIN:VCALENDAR | カレンダーの開始 | — |
VERSION:2.0 | iCalendarのバージョン | 2.0固定 |
PRODID | 作成元の識別子 | -//Company//Tool//JA |
BEGIN:VEVENT | イベント開始 | — |
UID | イベントの一意ID | [email protected] |
DTSTAMP | 作成タイムスタンプ(UTC) | 20260429T120000Z |
DTSTART | 開始日時 | 20260501T100000Z |
DTEND | 終了日時 | 20260501T110000Z |
SUMMARY | タイトル | 会議名 |
UID は同じUIDでイベントを再送すると更新扱いになるため、必ず一意にします。
よく使う追加プロパティ
| プロパティ | 内容 | 例 |
|---|---|---|
DESCRIPTION | 詳細説明 | 参加URL: https://... |
LOCATION | 場所 | 渋谷オフィス3F |
URL | 関連URL | https://example.com/event |
ORGANIZER | 主催者 | mailto:[email protected] |
ATTENDEE | 参加者 | mailto:[email protected] |
CATEGORIES | カテゴリ | MEETING,WORK |
STATUS | 状態 | CONFIRMED / TENTATIVE / CANCELLED |
PRIORITY | 優先度 | 0(無)〜9(最低) |
日時フォーマット
ICSの日時はUTCまたはローカル+TZIDで書きます。
UTC形式(推奨)
DTSTART:20260501T100000Z
DTEND:20260501T110000Z
末尾の Z がUTCを意味します。タイムゾーン非依存で扱いやすい。
ローカルタイム + タイムゾーン
DTSTART;TZID=Asia/Tokyo:20260501T190000
DTEND;TZID=Asia/Tokyo:20260501T200000
タイムゾーン定義(VTIMEZONE)も合わせて含める必要があります。
終日イベント
DTSTART;VALUE=DATE:20260501
DTEND;VALUE=DATE:20260502
DTEND は翌日の日付を指定するのが仕様上の正しい書き方(exclusive)。
繰り返しイベント(RRULE)
毎週・毎月などの繰り返しイベントは RRULE プロパティで表現します。
毎週月曜の朝会
DTSTART;TZID=Asia/Tokyo:20260504T090000
DTEND;TZID=Asia/Tokyo:20260504T093000
RRULE:FREQ=WEEKLY;BYDAY=MO
毎月15日の支払い日
DTSTART;VALUE=DATE:20260515
RRULE:FREQ=MONTHLY;BYMONTHDAY=15
平日のみ毎日
RRULE:FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR
終了日付付き繰り返し
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20261231T235959Z
回数指定
RRULE:FREQ=DAILY;COUNT=10
主な FREQ 値
| 値 | 意味 |
|---|---|
DAILY | 毎日 |
WEEKLY | 毎週 |
MONTHLY | 毎月 |
YEARLY | 毎年 |
文字エスケープルール
ICSは行ベースの形式で、特定の文字をエスケープする必要があります。
| 文字 | エスケープ |
|---|---|
カンマ , | \, |
セミコロン ; | \; |
バックスラッシュ \ | \\ |
| 改行 | \n |
DESCRIPTION:Zoomリンク:\nhttps://zoom.us/j/123\n\nパスワード: 1234
行が75オクテットを超える場合は折り返し(CRLF + スペース)が必要:
DESCRIPTION:これは非常に長い説明文で75オクテットを超えるため折り返しが必要にな
るケースを示しています。
サンプルコード(言語別)
JavaScript / TypeScript
function generateICS(event: {
uid: string;
title: string;
description: string;
location: string;
start: Date;
end: Date;
}): string {
const formatDate = (d: Date) =>
d.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
const escape = (s: string) =>
s.replace(/\\/g, '\\\\').replace(/\n/g, '\\n')
.replace(/,/g, '\\,').replace(/;/g, '\\;');
return [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//taskari.me//ICS Generator//JA',
'CALSCALE:GREGORIAN',
'BEGIN:VEVENT',
`UID:${event.uid}`,
`DTSTAMP:${formatDate(new Date())}`,
`DTSTART:${formatDate(event.start)}`,
`DTEND:${formatDate(event.end)}`,
`SUMMARY:${escape(event.title)}`,
`DESCRIPTION:${escape(event.description)}`,
`LOCATION:${escape(event.location)}`,
'END:VEVENT',
'END:VCALENDAR',
].join('\r\n');
}
// ダウンロードリンクを生成
function downloadICS(content: string, filename: string) {
const blob = new Blob([content], { type: 'text/calendar;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
Python
from datetime import datetime, timezone
import uuid
def generate_ics(title: str, start: datetime, end: datetime,
description: str = '', location: str = '') -> str:
fmt = lambda d: d.astimezone(timezone.utc).strftime('%Y%m%dT%H%M%SZ')
def escape(s: str) -> str:
return s.replace('\\', '\\\\').replace('\n', '\\n') \
.replace(',', '\\,').replace(';', '\\;')
return '\r\n'.join([
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//taskari.me//ICS Generator//JA',
'CALSCALE:GREGORIAN',
'BEGIN:VEVENT',
f'UID:{uuid.uuid4()}@taskari.me',
f'DTSTAMP:{fmt(datetime.now(timezone.utc))}',
f'DTSTART:{fmt(start)}',
f'DTEND:{fmt(end)}',
f'SUMMARY:{escape(title)}',
f'DESCRIPTION:{escape(description)}',
f'LOCATION:{escape(location)}',
'END:VEVENT',
'END:VCALENDAR',
])
PHP
function generateICS($title, $start, $end, $description = '', $location = '') {
$fmt = fn($t) => gmdate('Ymd\THis\Z', $t);
$escape = fn($s) => str_replace(["\\", "\n", ',', ';'], ["\\\\", "\\n", "\\,", "\\;"], $s);
return implode("\r\n", [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//taskari.me//ICS Generator//JA',
'BEGIN:VEVENT',
'UID:' . uniqid('', true) . '@taskari.me',
'DTSTAMP:' . $fmt(time()),
'DTSTART:' . $fmt($start),
'DTEND:' . $fmt($end),
'SUMMARY:' . $escape($title),
'DESCRIPTION:' . $escape($description),
'LOCATION:' . $escape($location),
'END:VEVENT',
'END:VCALENDAR',
]);
}
HTTPレスポンスの設定
ブラウザでダウンロードさせる場合のヘッダー:
Content-Type: text/calendar; charset=utf-8
Content-Disposition: attachment; filename="event.ics"
URL購読型(ユーザーがカレンダーで購読登録するタイプ)の場合:
Content-Type: text/calendar; charset=utf-8
Cache-Control: no-cache, must-revalidate
各カレンダーアプリでの読み込み
| アプリ | 読み込み方法 |
|---|---|
| Googleカレンダー | 設定 → インポート/エクスポート → ICSファイル選択 |
| Outlook | カレンダー → 開く → ファイルからインポート |
| Apple Calendar | ファイル → 読み込み → ICSファイル選択 |
| iPhone | メールやSafariで .ics をタップ → カレンダーに追加 |
| Yahooカレンダー | インポート機能から |
URL購読型の場合は、各カレンダーで「URLから購読」を選びICSファイルのURLを貼り付けます。
よくあるトラブル
| 問題 | 原因 | 解決方法 |
|---|---|---|
| イベントがインポートされない | UIDがない/重複している | UIDを一意の値に |
| 時刻が9時間ずれる | DTSTART がUTC指定なのにローカル想定 | UTC変換するか TZID指定 |
| 日本語が文字化け | UTF-8でない | ファイルをUTF-8で保存 |
| 改行が反映されない | \n ではなく改行を入れている | DESCRIPTION 内では \n 文字列 |
| 終日イベントが翌日にもまたがる | DTEND の意味を勘違い | DTEND は終了日翌日(exclusive) |
まとめ
- ICSファイルはRFC 5545準拠の標準フォーマット
- 必須は VERSION・PRODID・UID・DTSTAMP・DTSTART・SUMMARY
- 日時はUTC(末尾Z)が無難。タイムゾーン指定なら VTIMEZONE 必須
- 改行コードは
\r\n、エスケープは\,\;\\\n
関連ツール: ICSファイル作成ツール ではフォームに入力するだけでICSファイルを生成できます。Googleカレンダー・Outlookで読み込めるエクスポートに対応。会議通知メールの添付や、イベントページの「カレンダーに追加」ボタンに使えます。