ICalendar

iCalendar是“日历数据交换”的标准（RFC 5545）。
此标准有时指的是“iCal”，即苹果公司的出品的一款同名日历软件（见iCal），这个软件也是此标准的一种实现方式。
iCalendar允许用户通过电子邮件的方式发送“会议请求”或“任务”。收信人使用支持iCalendar邮件客户端，便可以很方便地回应发件人，接受请求或另外提议一个新的会议时间。
iCalendar已得到很多产品的支持。通常情况下，iCalendar数据是使用电子邮件交换，但它也可以独立使用，而不局限于某种传输协议。例如，可以通过WebDav伺服器或SyncML来进行共享与修改。简单的网页伺服器（只使用HTTP协议）也常常被用来分发公共事件的iCalendar数据，或发布个人的时间谋划安排。发布者可以使用hCalendar把iCalendar数据嵌入到网页中。（hCalendar是一种通过（X）HTML来表现iCalendar的微格式）

**历史与设计**
iCalendar是由互联网工程任务组的日历与计划工作组设计（OpenText公司的Anik Ganguly主导），并由莲花公司的Frank Dawson和微软的Derik Stenerson发表。iCalendar本身是基于互联网邮件协会（IMC）的vCalendar开发设计而来的。它通常是以文件名后缀为.ics或.ifb的文本文件保存的。现有标准是于2009年九月发布的 RFC 5545，上一个标准是 RFC 2445 date=20191017103324 。
以.ics为后缀名的文件（在Apple Mac系统中使用"iCal"类型代码），表示该文件包含了日历和计划信息。而以.ifb为后缀名的文件（在Apple Mac系统中使用"iFBf"类型代码），表示该文件包含 了空闲和忙碌时间信息。
通常iCalendar使用UTF-8字符编码；但也可以使用MIME中的charset参数来指其它的字符编码（如果它的传送协议支持MIME的话）。
在iCalendar文件中，每一行必须以CR+LF（十六进制代码为0D0A）为结尾。每一行不得超过75字节/八位元组。如果一行数据长于这个限制，则必须换行；后面一行使用空格符（十六进制代码为20）或者制表符（十六进制代码为09）作开始，以表示本行内容是上面一行内容的继续。内容数据中的换行符，可以反斜杠符'/'后跟数字（UTF-8中为5C 6E或5C 4E）来表示。
iCalendar的MIME类型被定义为text/calendar。

**局限和发展**
iCalendar格式只是被设计用来传送日历和计划表数据，如事件；而故意没有定义操作这些数据的行为。因为，在编写程序时需要协商如何操作它们。
iCalendar本意是提供一种公共格式来定义开放的互联网可交换的日历和计划表数据。当这些特性被广泛支持应用后，很多性能问题逐渐显现出来了。比如，大多数应用都不支持旅行（VJOURNAL）。"在标准中，循环重复的会议有一些含糊不清，这导致在现有不同的应用之间仍然无法真正地互动。"
iCalendar中的日历无法兼容非格里高利历，比如以色列的希伯来历和沙特阿拉伯的伊斯历都是阴历。
“日历访问协议”备忘录（ RFC 4324 date=20191017103337 ）首次尝试建立一个统一的创建实时日历系统。可能是因为过于复杂，这个协议最终被放弃了。
无论如何，像GroupDav和CalDAV这些基于iCalendar的协议已经越来越广泛地应用在客户端和服务端软件包中了。
互联网工程任务组的日历与计划工作组 已经提交了关于iCalendar标准的附加修改提案。但这个工作组于2011年一月份被解散了。他们大部分工作重心转移到了前一个标准的条款解释。而后续的创新工作由日历和计划协会（简称为Calconnect）来完成。

**技术标准**

**核心对象**
iCalendar中的顶级元素是日历和计划核心对象，一组日历和计划信息。通常情况下，这些信息应该只包含单一的iCalendar对象。但可以声明一个组包含多个iCalendar对象。
第一行必须是"BEGIN:VCALENDER"，最后一行必须是"END:VCALENDER"；两行之间数据称之为"icalbody"。
icalbody由一系列日历属性和一个以上的日历组件组成。日历属性被应用于整个日历。日历组件则是由若干日历属性描述成的一个日历语义。比如，日历组件可以指定一个事件、一个待办事项列表、一个旅行事项、时区信息、繁忙/空闲时间信息，或者一个警报。在许多协议实现（比如Google Calendar）中不允许出现空行。
下在是一个简单的iCalendar对象示例，它描述了法国国庆日，即从1997年七月14日 17:00到1997年七月15日 03:59:59的巴士底日。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR

**事件（VEVENT）**
VEVENT描述一个事件，在日历上一系列计划好的时间点。通常，当用户接受一个日历事件，这将导致在那个时间里，用户被认为是忙碌的。VEVENT可以包含一个VALARM对象来允许一个警报。事件应该有一个DTSTART来描述事件的开始时间，和一个DTEND来描述事件的结束时间。如果事件是循环的，则DTSTART应该设置第一个事件的开始时间。
VEVENT同样可以应用在没有特定时间的日历事件上，比如周年纪念日、每日提醒。
如果你需要发送取消事件的请求。那么在请求中事件组件中，UID属性应该与原事件一致并且，下面这些属性应该设置成cancel。
METHOD:CANCEL
STATUS:CANCELLED
为了发送事件的更新请求，除了设置UID和其它更新属性值外。还需要设置新序列值
SEQUENCE:
比如，第一个更新版本
SEQUENCE:1
在Microsoft Outlook中，SUMMARY属性应当与"Appointment"中的"Subject"项一致，DESCRIPTION 属性紧跟着SUBJECT属性。另外，Outlook 2003要求指定UID和DTSTAMP属性。

**待办事项（VTODO）**
VTODO描述一条待办事项。
下面的例子描述了一个应于1998年四月15日的待办事项。届时一个响铃将会响起。在待办事项完成前，将会一小时提醒一次，共提醒四次。SEQUENCE属性显示这条提醒在创建之后，还被修改了两次。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ABC Corporation//NONSGML My Product//EN
BEGIN:VTODO
DTSTAMP:19980130T134500Z
SEQUENCE:2
UID:uid4@host1.com
ACTION:AUDIO
TRIGGER:19980403T120000
ATTACH;FMTTYPE=
files/ssbanner.aud
REPEAT:4
DURATION:PT1H
END:VTODO
END:VCALENDAR

**旅行事项（VJOURNAL）**
VJOURNAL是一个旅行事项。它们将一段描述文字关联一个详细的日历日期上，这可以被用户记录活动和成长日志，或者描述待办事项的进展。VJOURNAL日历组件不会影响日历上的时间状况，所以不会对空闲和繁忙状态有任何影响。在实践上，有很少的程序支持VJOURNAL项，不过也有存在一些实现。比如：Plum Canary's Chirp软件将VJOURNAL和VTODO一起使用。KDE中的KOrganizer也支持VJOURNAL。
下面就是旅行事项的例子
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ABC Corporation//NONSGML My Product//EN
BEGIN:VJOURNAL
DTSTAMP:19970324T120000Z
UID:uid5@host1.com
ORGANIZER:
STATUS:DRAFT
CLASS:PUBLIC
CATEGORIES:Project Report, XYZ, Weekly Meeting
DESCRIPTION:Project xyz Review Meeting Minutes\n
Agenda\n1. Review of project version 1.0 requirements.\n2.
Definition
of project processes.\n3. Review of project schedule.\n
Participants: John Smith, Jane Doe, Jim Dandy\n-It was
decided that the requirements need to be signed off by
product marketing.\n-Project processes were accepted.\n
-Project schedule needs to account for scheduled holidays
and employee vacation time. Check with HR for specific
dates.\n-New schedule will be distributed by Friday.\n-
Next weeks meeting is cancelled. No meeting until 3/23.
END:VJOURNAL
END:VCALENDAR
注意: 这个例子中来自于 RFC 2445 date=20191017103324 。在这里将原文中的CATEGORY修正为CATEGORIES，这是原文中的一个错误。

**空闲/繁忙时间（VFREEBUSY）**
VFREEBUSY被用在 空闲/繁忙时间 设置请求，这种请求的回应，以及繁忙时间的发布中。
下面就是一个系统时间发布的例子。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//RDU Software//NONSGML HandCal//EN
BEGIN:VFREEBUSY
ORGANIZER:
DTSTART:19980313T141711Z
DTEND:19980410T141711Z
FREEBUSY:19980314T233000Z/19980315T003000Z
FREEBUSY:19980316T153000Z/19980316T163000Z
FREEBUSY:19980318T030000Z/19980318T040000Z
URL:
END:VFREEBUSY
END:VCALENDAR

**其它组件类型**
其它组件类型还有VTIMEZONE（时区）和VALARM（警报）。还有一些组件允许包含其它组件（VALARM通常被包含于其它组件）。

**发布更新**
当计划事件更改，UID字段将发布更新。首先事件创建时会生成一个全局唯一标识符作为UID。之后当有一个事件跟随这个UID发布，则认为这是早先事件的修改版本，并替换掉它。

**日历扩展**
iCalendar支持私有扩展，即在属性名前冠以"X-"前缀。
比如：- X-RECURRENCE-ID- X-EPOCAGENDAENTRYTYPE- X-FUNAMBOL-AALARMOPTIONS- X-FUNAMBOL-ALLDAY- X-MICROSOFT-CDO-ALLDAYEVENT- X-MICROSOFT-CDO-BUSYSTATUS- X-WR-CALNAME- X-WR-CALDESC- X-WR-RELCALID- X-WR-TIMEZONE- X-PUBLISHED-TTL