BaseHalf
全部文章

用 BaseHalf 和 AI 入门 RFC 3339 时间戳

我们在 BaseHalf 里打开真实的 rfc3339-timestamps 文件夹,把格式、偏移和限制笔记摆成卡片,旁边放着 RFC 3339 的本地副本,把这些笔记写进练习卡片的 upstream,再在 Agent Area 用 Claude Code 把四道时间戳题判为正确。

检查一个时间戳时,最好把格式、偏移和限制放在各自的卡片上,让 RFC 待在同一个文件夹里,让智能体同时看到这些笔记和练习答案。我们在桌面上建了一个普通文件夹,放进六份短 Markdown 和一份 RFC 3339 的本地副本,再用 BaseHalf 打开。窗口标题变成 rfc3339-timestamps,侧栏列出每一个文件,每个文件变成卡片。我们在右侧 Agent Area 启动了 Claude Code,并选中了练习卡片。

磁盘上的路径是 Desktop/basehalf-learn-sessions/rfc3339-timestamps/。画布上的文件是这些:

rfc3339-timestamps/
  00-goal.md
  01-format.md
  02-offsets.md
  03-restrictions.md
  04-practice.md
  rfc3339.txt
  sources.md

标题为 rfc3339-timestamps 的 BaseHalf 窗口:侧栏列出 00-goal 到 sources,其中包括 rfc3339.txt;画布上是目标、三张概念卡片、RFC 文本、sources,以及 04-practice,概念卡片和 sources 有连线进入练习笔记。

每张卡片写了什么

00-goal.md 划定范围:把一个 Internet 时间戳解析成完整日期、时间和偏移;区分 Z、+00:00 和 -00:00;拒绝缺少偏移或使用小时 24 的时间戳;再对照 RFC 3339 核对四道练习。这个文件夹学的是 RFC 3339,它是 ISO 8601 的一个 profile,并不是 ISO 标准本身。

01-format.md 记下第 5.6 节的语法:date-time 是 full-date,然后是 T,然后是 full-time。年份是四位数字。秒是必需的,小数秒是可选的。full-time 一定带 time-offset。该节有一条说明:T 和 Z 也可以用小写;应用为了可读,也可以在日期和时间之间用空格代替 T。空格是应用自己的选择,并不在 ABNF 里。

02-offsets.md 把 Z 写成 UTC,把数字偏移写成“本地时间减去 UTC”,所以 18:50:00-04:00 和 22:50:00Z 是同一时刻。它还记下第 4.3 节的区分:-00:00 表示 UTC 时间已知、本地偏移未知,这和 Z 或 +00:00 在语义上不同,后两者意味着 UTC 是该时间的首选参考点。没有偏移的未限定本地时间,不适合在 Internet 上交换。字母时区标签不是这种格式的一部分。

03-restrictions.md 记下第 3 节的四位年份规则,第 5.7 节的小时范围 00 到 23(ISO 8601 允许小时为 24,本 profile 不允许),以及闰秒规则:只有在插入闰秒时,time-second 才可以是 60。它写到了 1990-12-31T23:59:60Z 和 1990-12-31T15:59:60-08:00,并说明在闰秒正式宣布之前,应用不应生成插入闰秒的时间戳。

sources.md 链接了 RFC 3339(Klyne 与 Newman,2002 年 7 月),本地副本是 rfc3339.txt。它也写明:我们没有打开 ISO 8601,那份标准不能像 RFC 这样免费下载。

练习笔记上的 upstream

练习笔记把三张概念卡片和 sources.md 写进了 upstream 列表。画布上,从 01-format、02-offsets、03-restrictions 和 sources 出发的线,连进了 04-practice。文件开头是:

upstream:
  - 01-format.md
  - 02-offsets.md
  - 03-restrictions.md
  - sources.md

这份列表会留在文件里。选中状态不会:它只在 BaseHalf 打开时存在 .bh/cache/selection.yaml 里。我们选中了练习卡片,状态栏显示 04-practice,然后才请 Claude Code 判题。

四道练习

练习卡片要求每道题给出简短答案和一行理由,并优先依据卡片和 RFC 3339,而不是凭记忆中的规则。

  1. 解析 RFC 3339 第 5.8 节的例子 1996-12-19T16:39:57-08:00。它对应的 UTC 时间是什么?

  2. 看 2026-11-15T06:00:00Z、2026-11-15T06:00:00+00:00 和 2026-11-15T06:00:00-00:00。它们是同一瞬间吗?意思一样吗?

  3. 按第 5.6 节的语法,2026-11-15T06:00:00 是合法的 date-time 吗?2026-11-15T24:00:00Z 呢?

  4. 按 RFC 3339,1990-12-31T23:59:60Z 合法吗?2026-11-15T06:00:00z(小写 z)符合第 5.6 节的语法吗?

我们的答案:

  1. 1996-12-20T00:39:57Z。第 5.8 节直接给出了这次换算:16:39:57、偏移 -08:00,对应第二天 UTC 的 00:39:57。这也符合第 4.2 节:减去偏移(加上八小时)就得到 UTC。

  2. 它们表示同一瞬间,即 UTC 的 06:00:00。意思并不一样。第 4.3 节说,-00:00 表示 UTC 时间已知、本地偏移未知,这和 Z 或 +00:00 在语义上不同,后两者意味着 UTC 是该时间的首选参考点。

  3. 不合法,也不合法。2026-11-15T06:00:00 没有 time-offset,按第 5.6 节它既不是 full-time,也不是 date-time;第 4.4 节也不接受未限定的本地时间用于 Internet 交换。2026-11-15T24:00:00Z 在本 profile 中不合法:第 5.7 节写明,虽然 ISO 8601 允许小时为 24,本 profile 只允许 00 到 23。

  4. 合法,而且小写 z 在语法上允许,但有一条保留。1990-12-31T23:59:60Z 是 1990 年末插入的闰秒;第 5.8 节就用了这个例子,第 5.7 节允许在插入闰秒时把 time-second 写成 60。第 5.6 节的第一条说明写道,T 和 Z 也可以是小写的 t 或 z,所以 2026-11-15T06:00:00z 符合语法。同一节还写,生成这种格式的应用 SHOULD 使用大写;在某些环境(例如 XML)里,使用该格式的规范 MAY 进一步要求必须大写。

rfc3339-timestamps 画布和右侧 Agent Area:Claude Code v2.1.325(Opus 5.5,xhigh,Claude Ultra)加载了 BaseHalf skill,阅读了 rfc3339.txt,并指出 04-practice.md 里的四道答案都正确,还引用第 5.8 节核对了第一题的 UTC 换算。

Claude Code 实际说了什么

请把回复当作草稿。这次会话里,Claude Code(v2.1.325,窗口里显示为 Opus 5.5、xhigh effort、Claude Ultra)说四道答案都正确,每一道都符合 upstream 笔记和本地的 rfc3339.txt,并且它没有改任何文件。这次运行用了 1 分 24 秒。练习相关文件在磁盘上的时间戳,与会话开始前相同。

第一题,它引用了第 5.8 节:这个例子等价于 UTC 的 1996-12-20T00:39:57Z。它还引用了第 4.2 节:数字偏移是“本地时间减去 UTC”,负偏移通过加上绝对值来处理。16:39:57 加八小时是 24:39:57,进到 12 月 20 日的 00:39:57。我们对照本地 RFC 核对了这两处,引文成立。它在引文旁边打印的一些行号偏了几行,所以我们以章节正文为准,不以那些行号为准。

第二题,它同意它们是同一瞬间,即 UTC 的 06:00:00,意思却不同。它完整引用了第 4.3 节关于 -00:00 与 Z 或 +00:00 的说明,并指出我们的答案沿用了这段措辞,包括 “imply” 这个词。它还指向第 2 节对 Z 的定义:它是表示 UTC 偏移为 00:00 的后缀。这两处我们都核对过,本地副本里有。

第三题,它同意两个字符串都不合法,但读得更紧一些。缺少偏移的字符串不符合第 5.6 节的语法,因为 full-time 是 partial-time 加上 time-offset。把第 4.4 节当作支持是可以的,但它说那一节更多是理由:它把未限定本地时间的互操作问题称为“对 Internet 不可接受”,然后要求系统必须与 UTC 同步。“第 4.4 节也不接受”稍微说重了;单凭语法就足以判定这个字符串不合法。我们核对了第 4.4 节,这个区分是对的。

关于小时 24,它同意应当看第 5.7 节,并引用了本 profile 只允许 00 到 23 的那一句。接着它指出我们题目里的一个措辞问题。第 5.6 节的 ABNF 写的是 time-hour = 2DIGIT,00-23 只出现在注释里。单独看,2DIGIT 也能匹配 24。只按 ABNF 记号实现的校验器会接受这个小时;注释里的范围,再加上第 5.7 节的正文,才把它排除掉。题目问的是“按第 5.6 节的语法”。我们核对了这条产生式;范围写在注释里,真正的限制在第 5.7 节。

同一会话滚到末尾:它认为小写 z 的保留说明是准确的,指出限制笔记里对闰秒例子的引用偏松,并显示这次运行用了 1 分 24 秒。

第四题,它同意 1990-12-31T23:59:60Z 合法,引用了第 5.8 节的例子(“1990 年末插入的闰秒”),以及第 5.7 节允许在插入闰秒时把 time-second 写成 60 的规则。附录 D 的表里也有 1990-12-31。它同意小写 z 是允许的,并引用了第 5.6 节第一条说明里关于 t 和 z 的句子。它还说,关于使用方规范 MAY 要求大写的保留是准确的;带有 MAY 和 SHOULD 的那段话本身没有 NOTE: 标签,它和前后两条说明处在同一缩进,所以把它叫作“同一条说明”是说得通的。MAY 那句并不在我们的格式笔记里,答案是直接从 RFC 里取的。我们核对了这些段落,引文和排版都成立。

然后它列出的是笔记里的引用问题,不是练习答案的问题。限制笔记里有一处偏松:它说第 5.7 节和第 5.8 节的例子给出了那两个 1990 年的字符串;其实只有第 5.8 节给出了 1990-12-31T23:59:60Z 和 1990-12-31T15:59:60-08:00。第 5.7 节给出的是一般形式 XXXX-06-30T23:59:60Z 和 XXXX-12-31T23:59:60Z。1990 年的例子应当只标第 5.8 节,或标第 5.8 节加上附录 D。我们核对过,这一点是对的。它还说,偏移笔记把 Z 和 +00:00 的 “imply” 转述成了 “name”,而练习答案用的是 RFC 的原词;“不适合在 Internet 上交换”也接近原文的 “unacceptable for the Internet”。这些措辞并不改变判分。

这次会话能说明什么,不能说明什么

四道做完的题只是起点,并不是读完了 RFC 3339。我们没有走闰年代码、最后一个例子里荷兰历史上那 19 分钟的偏移,也没有走第 7 节的安全说明。模型可能引错章节或行号;本地 RFC 才是核对依据。这次我们核对过的章节引文是成立的,但有几处行号并不准。以后还可以在同一个文件夹里,把闰秒例子的引用收紧,再接着往下学。