1. カレンダーアプリは「この回だけ削除」を繰り返す
子どもの習い事は毎週火曜の 17 時、ただし 8 月はお休みで、年末年始も休み。町内の資源ごみは第 1・第 3 水曜だが、年末年始は収集がない。ジムは毎週月曜が定休で、年末年始とお盆は休館。「毎週」「毎月」に「ただし」が付く予定は、暮らしの中にいくらでもある。
スマホのカレンダーに「毎週火曜 17 時」を入れるところまではよい。8 月の 4 回と年末年始の 1 回は、その回を開いて「この予定のみ削除」を 5 回繰り返す。来年になれば、また 5 回。cron で書く人も同じで、「翌年が来る前に手でコメントアウトする」運用が定番になっている。
どちらも、「除く」という言葉が道具の側に無いことが人間側に波及した姿である。除く言葉があれば、定義の中で閉じる。
2. 火曜の列から、8 月と年末年始の列を引く
# 毎週火曜 17 時の習い事。ただし 8 月と年末年始は休み
premise JP { calendar-system: Gregorian; tz: "Asia/Tokyo"; wkst: Mon }
@JP
tue = everyDay |> filter(d => weekday(d) == Tue)
august = everyDay |> filter(d => month(d) == 8)
yearEnd = [2026-01-01..2026-01-03, 2026-12-29..2026-12-31] covering: 2026..2026
(tue \ (august | yearEnd)) |> at(T17:00)
tueは毎週火曜の列。augustは 8 月の毎日の列。yearEndは年末年始の表。|が和、\が差。「8 月と年末年始を束ねて、火曜の列から引く」。- 引いてから
at(T17:00)で 17 時を付ける(目覚ましの回と同じ器)。

夏休みの前後を聞いてみる:
$ kairos list --from 2026-07-20 --to 2026-09-10 lesson.kairos 2026-07-21T17:00 2026-07-28T17:00 2026-09-01T17:00 2026-09-08T17:00 # 被覆サマリ # yearEnd covering 2026-01-01..2026-12-31 残走路 113 日
8 月の火曜 4 回(8/4・11・18・25)が消え、7 月末と 9 月頭はそのまま残る。2026 年の全体では、火曜 52 回から47 回になる。「この回だけ削除」を 5 回する代わりに、\ を 1 回書いた。
3. 「8 月」は規則で書ける、「年末年始」は表が要る
2 つの除外の書き方が違うのには理由がある。
- 8 月は規則で決まる。「月が 8 なら」は毎年同じなので、
month(d) == 8と書けば表は要らない。 - 年末年始は人が決める。12 月 29 日から 1 月 3 日までなのか、28 日から 4 日までなのかは、教室や自治体の案内で 決まる。規則ではなく事実なので、表に書く。表には
covering: 2026..2026——「この表は 2026 年の分」——を添える。
祝日も同じで、習い事が祝日も休みなら、祝日の表を引く列に足す。2026 年は 5 月 5 日(こどもの日)・9 月 22 日(国民の休日)・11 月 3 日(文化の日)が火曜に当たるので、tue \ (august | yearEnd | national) と書けば 47 回から 44 回になる。祝日表の書き方は「月 2 回」の回の §3 にある。
4. 表の外に出ると、鳴らさずに言う
年末年始の表は 2026 年分しか書いていない。年を跨いで聞いてみる:
$ kairos list --from 2026-12-01 --to 2027-02-01 lesson.kairos 2026-12-01T17:00 2026-12-08T17:00 2026-12-15T17:00 2026-12-22T17:00 # ⚠ 範囲外 2027-01-01..2027-02-01(yearEnd covering 2026-01-01..2026-12-31) # 被覆サマリ # yearEnd covering 2026-01-01..2026-12-31 残走路 -31 日
12 月の 4 回は出て、12 月 29 日は消える。2027 年 1 月の火曜は 1 つも出ない。代わりに「2027 年 1 月は表の外だ」という1 行が出る。2027 年の年末年始がいつ休みかは表に無いので、言語は 1 月 5 日に 17 時を付けない。「鳴る」のでも「鳴らない」のでもなく、「表が無い」と言う。
カレンダーアプリは黙って 1 月 5 日に通知を出す。去年「この回だけ削除」した記憶は、今年の 1 月には効かない。Kairos では、表の外は黙らない(祝日表は黙って腐る・目覚ましの回の §5)。直し方は、表に 2027 年の年末年始を足して covering: を 2026..2027 に延ばすだけである。
5. 落とし穴
- 引くのは、時刻を付ける前。
tue \ augustは日の列どうしの引き算で、同じ日なら消える。17 時を付けた後に 日の列を引いても、17 時の点と日の点は別物なので消えない。「引いてからat」の順を守る。 - 「8 月」の境界は暦の月。8 月 1 日から 31 日まで。夏休みが 7 月 21 日から 8 月 31 日なら、それは規則ではなく 事実なので、年末年始と同じく表に書く(
[2026-07-21..2026-08-31])。 - 評価範囲は定義の外。「今年の 4 月から始めた習い事」は、定義に 4 月を書くのではなく、聞くときの
--fromを 4 月にする。定義は「いつでも成り立つ規則」、範囲は「いつからいつまで聞くか」。半開区間の回の[from, to)がここで効く。
6. 動かす
毎朝「今日は点があるか」を聞いて、あれば通知する型は月末最終営業日の自動実行まで通すの型 1、Windows なら「今日は Windows Update の日です」の §6 のガイドがそのまま使える。スマホのカレンダーに入れるなら --ics で書き出す(.ics 取り込みの事件簿)。47 回ぶんの予定が、「この回だけ削除」なしで入る。
まとめ
- 「ただし 8 月は休み」を、カレンダーアプリは「この回だけ削除」の繰り返しで表す——除く言葉が無いから
- Kairos では列を引く:
(tue \ (august | yearEnd)) |> at(T17:00)。2026 年は 52 回から 47 回 - 規則で決まる除外(8 月)は
filter、人が決める除外(年末年始)は表+covering: - 表の外の月は、時刻を付けずに「表の外」と言う。黙って通知が来るより、ずっといい
- 引くのは時刻を付ける前。「いつから聞くか」は定義でなく
--fromで
▶ Playground で定義を実行する——2026 年の火曜 47 回が出る。コメントにある「祝日も休み」の行と入れ替えると 44 回になる。ブラウザ内で完結し、何も送信しない。
Kairos はスケジュール定義言語です。仕様と参照実装はGitHub で公開しています。

コメント