表示完整的一天时,应包含其开始时间,并排除次日的开始时间。若要在 Mac 日历中标记发布日期,请创建全天事件;在 iCalendar 数据中,明确的结束日期表示事件之外的第一天。

本指南使用虚构的发布日期:2027 年 6 月 18 日。任务是在 Mac 日历中添加一个完整的发布日期,将其导出并检查边界。掌握同样的思路,也能帮助你在日期从日历传到电子表格和自动化流程时发现错误。

排他的次日边界是什么意思?

对于这个虚构的发布日期,包含的日期是 6 月 18 日。6 月 19 日是排除在外的第一天。用左闭右开的区间表示,该范围为 [2027-06-18, 2027-06-19):方括号表示包含起点,圆括号表示不包含终点。

iCalendar 标准规定,事件的 DTSTART 是包含的,而 DTEND 不包含在内。全天事件的起止值均使用日期值。因此,结束日期设为次日,就表示完整的一天。仅含日期的值不得带有 TZID 参数。RFC 5545,事件组件和时区标识符。

下面的示例片段只展示了两个边界属性,并非完整、可导入的日历文件:

DTSTART;VALUE=DATE:20270618
DTEND;VALUE=DATE:20270619

下表将此规则应用于虚构的发布日期安排。请将最后一列理解为排除在外的第一天,而不是另一个发布日期。

预期涵盖范围 包含的开始日期 不包含的结束日期
仅 6 月 18 日 2027 年 6 月 18 日 2027 年 6 月 19 日
包含 6 月 18 日至 20 日 2027 年 6 月 18 日 2027 年 6 月 21 日
仅 6 月 30 日 2027 年 6 月 30 日 2027 年 7 月 1 日

在 Mac 日历中创建发布日期

首先,打开一个允许你创建事件的日历。此任务需要使用日历的全天事件控件;不需要编程工具。

  1. 打开日历并前往 2027 年 6 月 18 日。
  2. 在窗口顶部选择 日 或 周。
  3. 在 6 月 18 日的小时网格上方,双击 all-day 区域。
  4. 将事件标题设为中性的 示例发布日期。
  5. 确认标记仅占据 6 月 18 日。

Apple 说明,在 日 或 周 视图中双击全天区域即可创建全天事件。Apple 另有说明,可通过在多个日期上拖动来创建多日事件。本例请使用单日操作。在 Mac 上的日历中设置全天、多日或重复事件。

先检查日历上的可见标记:它应涵盖预期日期,不能延续到 6 月 19 日。排他边界描述的是数据中如何表示日期范围,并非要求将可见标记延伸到另一日。

导出事件并检查日期边界

在日历列表中选择该事件所属的日历,然后选择 文件 > 导出 > 导出。将生成的 .ics 文件保存到方便的位置。此操作会导出所选日历中的事件,因此,如果该日历包含多个事件,导出的文件也会包含多条事件记录。Apple 说明此导出使用 .ics 格式。在 Mac 上导入或导出日历。

在 Finder 中选中导出的文件,然后使用 文件 > 打开方式,在文本编辑器(例如文本编辑)中打开它。Apple 说明,可以通过这种方式为单个文件选择打开应用。在 Mac 上选择打开文件的应用。

找到 示例发布日期,然后检查周围的事件记录。将其中的开始和结束属性与上面的示例片段进行比较。出现其他属性是正常的;请重点查看日期值及其类型。

如果全天事件既没有 DTEND,也没有 DURATION,标准会将其时长设为一天。因此,未显式指定结束时间并不自动意味着有问题。RFC 5545,事件组件。

将导出文件用作诊断副本。如果可见事件覆盖的日期不正确,请在日历中修正,然后重新导出。这样,你的检查就能对应到实际创建的事件。

区分民用日期、时刻、偏移量和命名时区

将发布日期移入其他工具之前,先确认该工具需要哪种类型的值。日历标签和时间戳回答的是不同问题。

概念 示例值 表示的内容
民用日期 2027-06-18 不含时钟时间的一个日历日期
时刻 2027-06-18T10:00:00Z 时间线上的一个点
数字 UTC 偏移量 +02:00 本地时间与 UTC 之间的时差
命名时区 Europe/Paris 其规则决定适用偏移量的时区

RFC 3339 定义了表示时刻的时间戳格式,其中包括数字偏移量和 UTC 标记 Z。它明确将区间描述排除在其范围之外。因此,一对 RFC 3339 时间戳仍需要另行约定是否包含终点。RFC 3339,范围和日期/时间格式。

例如,虚构时间戳 2027-06-18T12:00:00+02:00 和 2027-06-18T10:00:00Z 表示同一时刻。二者都不表示完整的发布日期。为日期添加时间和偏移量,会改变你记录的信息。RFC 3339,本地偏移量。

命名时区提供计算本地时间和适用偏移量的规则。IANA 维护这些规则,包括偏移量和夏令时行为的变化;操作系统和软件供应商则向用户分发更新。在不同日期计算边界时,单个数字偏移量无法替代整套规则。IANA 时区。

对于日历标记,请保留民用日期。如果后续任务要求确定哪些带时间戳的出版物属于该日,请先选择用于定义发布日期的命名时区,再在该时区中计算两个边界时刻。

Mac 自动化如何计算相同的范围?

Apple 的 Foundation 中,Date 表示独立于日历或时区的一个时刻。当你的输入只是 6 月 18 日时,这个名称可能会造成误解:民用日期需要结合日历上下文才能对应到一个时刻。Apple 建议使用 Calendar 进行日历运算。Date。

对于自动化流程,请明确指定日历系统和时区。Foundation 通过日历的可写属性 timeZone 提供其时区。明确这一选择,可以让维护自动化流程的人了解所采用的发布日期定义。Calendar.timeZone。

给定一个已知落在目标日期内的时刻,Calendar.dateInterval(of: .day, for:) 会获取该日历组件的开始时间和时长。此方法返回可选结果;自动化流程必须处理失败情况,不能悄悄换用另一个日期。dateInterval(of:for:)。

这里有一个重要的终点细节:Apple 将 DateInterval 定义为闭区间,即包含两个端点。要实现排他的发布日期边界,请使用计算出的边界并显式进行比较:start <= instant && instant < end。这是成员判定规则,而非完整程序。DateInterval。

不要假设每个本地日期都始于常规的午夜。Apple 的 startOfDay(for:) 会返回该日实际存在的最早时刻:如果有两个午夜,它会选取第一个;如果午夜不存在,则返回该日实际存在的第一个时刻。由日历计算出的边界会保留这一区别。startOfDay(for:)。

复用日期前检查边界

对于基于时间戳的工作流程,请对计算出的范围执行以下三点验收检查。这些预期结果直接来自明确排除终点的比较规则。

测试时刻 预期是否包含
恰好是当天的开始时刻 包含
严格位于两个边界之间的任意时刻 包含
恰好是次日的开始时刻 不包含

这项检查也说明了为什么不需要臆造一个类似 23:59:59 的最终时间。如果输入包含小数秒,晚于所选截止时间的值仍可能早于次日边界。与排他边界比较,就不必为“最后一刻”选择时间戳精度。

对于 Mac 桌面任务,最后确认 示例发布日期 仅占据 6 月 18 日,且导出的日期表示与这一覆盖范围一致。之后若将该日期用作时间戳筛选条件,请保留选定的日历和时区,包含开始时刻,并排除次日边界。

来源