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.0iCalendarのバージョン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関連URLhttps://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で読み込めるエクスポートに対応。会議通知メールの添付や、イベントページの「カレンダーに追加」ボタンに使えます。