日本語 · English(未訳)

標準 premise: Kyureki(旧暦)

Kyureki は朔(新月)の実データで月を刻む旧暦(太陰太陽暦・天保暦の様式)の premise。Gregorian からの 派生的定義with)であり、月の切れ目が周期規則からは生成できず天文事象(朔)で決まる暦法——テーブル リテラル(ADR-26)と射影一族(ADR-27/30)の適用例——を代表する。ユーザーが書けるのと同じ構文で書かれ、 中身を読めて差し替えられる「透明」さは Gregorian と同じだが、言語には同梱しない。同梱の 3 本 (GregorianFiscalISOWeek)が規則だけの premise であるのに対し、Kyureki は朔テーブルと月番号列 というデータ入り premise で、出所と版の統治(source:/asof:=ADR-26)を帯びる——「データは言語が 隠し持たず、premise が名指しで持ち込む」という設計判断による(§3)。本書が完全定義と各語・設計原理を担い、 言語仕様(../spec/)はテーブルリテラル(§3.8)と射影(§4.9)の意味論を担う。lunarMonth ほかの語は premise の公開語(言語の記述語ではない)なので統治は軽いが、名はいずれも仮であり 1.0 で一括確定する流儀に 従う(言語の記述語の命名確定状況は spec §5.4——premise 公開語はその表の外)。

1. 完全定義

premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"     # 国立天文台 暦要項。データ入り premise は source: 宣言必須寄り
  asof:   2026-02-02                          # 版: 最新の構成部分=令和9年〈2027〉暦要項の国立天文台発表日
  tz:     "Asia/Tokyo"                        # データの市民日を固定(朔は JST の壁時計値。F54・ADR-33)

  # 朔(新月)の瞬間列(JST・全 38 件)。先頭 2024-12-31T07:27 は令和6年暦要項の 12 月の朔で、
  # 2025 年 1 月前半(旧十二月の続き)に窓を張るための起点。転記元は design/40-examples/95-reference-data.md
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12]
    covering: 2024-12-31..2027-12-31                      # 有効範囲。外は「範囲外」の出自として評価註釈へ(I6)

  lunarStart = newMoons |> snapTo(day)        # 朔日=朔の瞬間を含む市民日(floor)。瞬間のまま渡さない(§7 (1))

  # 旧暦月番号のデータ列。newMoons が張る 38 窓と並行(先頭窓 [2024-12-31, 2025-01-29) が 12=旧十二月・
  # 最終窓 [2027-12-28, 覆域端 2028-01-01) も 12=旧十二月。edges: の発火は覆域端=ADR-37)。
  # 8 番目(2 個目の 6)が 2025 年の閏六月。導出(中気規則)は 95-reference-data.md に記録(§4)
  monthNos = [12, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11,
              12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
              12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  # 旧暦月名のデータ列(monthNos と同順。閏月は「閏六月」)
  monthNames = ["十二月", "一月", "二月", "三月", "四月", "五月", "六月", "閏六月", "七月", "八月", "九月", "十月", "十一月",
                "十二月", "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月",
                "十二月", "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]

  # 旧暦月。labels: が並行リストを窓列に結び、リスト長=窓数(38)を評価時に検査する(ADR-39・F62)。
  # edges: drop=データの端で黙って続けない。empties: error=朔日間(29〜30 日)の空窓はデータ破損の検出器
  lunarMonth = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNos)
  kyuMonth   = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNames)

  lunarDayNo = d => ordinalIn(day, lunarMonth, d)              # 旧暦日(月内第何日・1 起点)
  rokuyoNo   = d => (lunarMonth(d) + lunarDayNo(d)) mod 6      # 六曜番号(0=大安 … 対応表は §5)
}

読みは束縛名射影(ADR-30/34/39)——lunarMonth(d) が点 d の属する窓の月番号(1..12。閏月は前月と 同番号)を、kyuMonth(d) が月名を返す。意味論は 名前(d) ≡ labels[窓列序数] の一行で、窓列序数は 実効被覆域内の先頭マーカー起点の窓が 0(ADR-39 判断 3)。monthNos/monthNames の添字はこれに合わせて 先頭窓=旧十二月から並べてある。データ由来窓の epochOrdinal も「存在する最初の窓が 0」(F60=ADR-31 改訂)で本データの範囲では窓列序数と一致するが、紀元を跨ぐ歴史データでは epochOrdinal が負になるのに 対し窓列序数は常に 0 起点——別座標である(相乗りしない。ADR-39)。

2. 各語

種別 説明
newMoons テーブル(データ) 朔の瞬間列 38 件(JST・NAOJ 暦要項)。covering: の外は「範囲外」の出自(I6)。
lunarStart 導出ストリーム 朔日(朔の瞬間を含む市民日)。snapTo(day) は floor——21:36 の朔もその日に落ちる。
lunarMonth 窓+データラベル 朔日で切った旧暦月(全 38 窓。最終窓は覆域端まで確定=ADR-37)。labels: monthNos の束縛名射影で lunarMonth(d)=月番号。大の月(30 日)・小の月(29 日)は窓幅の帰結で、数える規則を持たない。
kyuMonth 窓+データラベル 同じ朔日窓に月名列を結んだ束縛。kyuMonth(d)=月名(「閏六月」を含む)。
monthNos 値リスト(データ) 各窓の旧暦月番号。lunarMonthlabels:——リスト長=窓数(38)を言語が検査する(ADR-39・§7 (4))。閏月は前月の番号の繰り返し。
monthNames 値リスト(データ) 各窓の旧暦月名。kyuMonthlabels:(monthNos と同順)。
lunarDayNo 値関数 旧暦日(旧暦月内の第何日・1 起点)。二窓 ordinalIn(ADR-30)。
rokuyoNo 値関数 六曜番号 (lunarMonth(d) + lunarDayNo(d)) mod 6。0=大安 1=赤口 2=先勝 3=友引 4=先負 5=仏滅(§5)。

Gregorian の公開語(daymonthweekdaymonthNo …)は派生でそのまま生きる(機構 A・ADR-17)。 グレゴリオ暦の month と旧暦の lunarMonth は独立の窓として同居し、互いに干渉しない。

3. データ入り premise——朔で切る暦法と I8(ADR-26)

旧暦の月は day span 日数規則 のような周期規則では生成できない。切れ目は朔という天文事象であり、 premise にできるのは「確定済みの朔列をデータとして受け取り、窓に変える」ことだけである。マーカーで窓を 切る受け皿(segmentBy)は最初からあり(ADR-07「月相のストリームで区切れば太陰暦」)、欠けていた 持ち込み口がテーブルリテラル(ADR-26・F5/F25)だった。

暦法純粋(I8)との整理——I8 が禁じるのは生成子がカレンダー(営業日・祝日という方針)に依存する ことであって、暦法がデータに依存することではない。朔で月を切る太陰太陽暦は「データに位相を求める 暦法」であり、Gregorian が数学的モデルであるのは Gregorian の性質であって暦法一般の要件ではない。 純粋性の区別は型でなく出自で付ける——だからデータ入り premise は source:(出所)と asof:(版)を 帯びる(ADR-26)。

同梱しない理由もここにある。規則だけの premise(GregorianFiscalISOWeek)は版を持たず陳腐化 しないが、Kyureki のデータは暦要項の発表(例年 2 月)のたびに伸び、出所の選択にも意味がある。言語が これを同梱すると「言語がデータを隠し持つ」ことになり、source:/asof: の統治が形骸化する。データは premise が名指しで持ち込む——本書は Kyureki を標準 premise 文書として解説するが、その実体はユーザーが 自分のデータで書く premise と同格である。

4. 月番号と閏月はデータ側(F37 の現実解)

旧暦の月(一月〜十二月)は中気規則で決まる: 各月が含む中気(二十四節気のうち太陽黄経が 30° の 倍数の 12 個)が月名を与え、雨水を含む月が正月。中気を含まない月が閏月で、前月の名を継ぐ (2025 年の閏六月)。

この規則自体は Kyureki に書かない。「前月の名を継ぐ」は隣接窓参照であり、label: 付与式の射程外 (I7・ADR-30)——F24/F37 の初出時から「旧暦月名はデータ側に倒すのが現実解」と確定している。そこで Kyureki は月番号を規則でなくデータ列monthNos)として持ち込み、導出の過程——朔・中気の一次データ から機械的に月番号を付ける手順と全 38 窓の表(導出 37 窓+覆域端確定の最終窓=ADR-37)——は ../design/40-examples/95-reference-data.md に記録して premise には結果だけを置く。2025 年の閏六月もその導出でデータから機械的に出現した(中気を含まない窓 [2025-07-25, 2025-08-23))。

分業をまとめると: どの日がどの旧暦月か(窓と月番号)はデータ、月内の座標lunarDayNo)と 六曜rokuyoNo)はデータの上の射影の算術、である。

5. 六曜の算術

六曜は「旧暦の月初でリセットされる 6 日周期」で、六曜番号 = (旧暦月番号 + 旧暦日番号) mod 6:

番号 0 1 2 3 4 5
六曜 大安 赤口 先勝 友引 先負 仏滅

旧暦 1 月 1 日は (1 + 1) mod 6 = 2 で必ず先勝(§6 に 3 年分の実証)。見かけは「リセット付きサイクル」 だが cycle は不要——月初リセットは新しい機構ではなく、窓内序数(ordinalIn)と剰余の算術に還元 される(../design/40-examples/02-cycles.md §2.4 の確定判断。年度ラベル・ISO 週番号と同根=ADR-27 の 根拠)。同じ月の中では六曜は 6 日ごとに巡り、月が替わる日に位相が飛ぶ(§6 の大安列で切れ目が見える)。

6. 実行例

以下はすべて実行検証されている(doctest。規約は ../reference/README.md)。doctest はブロック単体で実行 するため、各ブロックに §1 の定義から必要部分を再掲している(再掲部は §1 と字面同一——本体式と結果だけ 追えばよい)。 評価範囲の終端はプロトタイプの有界実体化(計算範囲= to+約 400 日)がデータ末尾の朔 2027-12-28 を含む 必要から 2027 年寄りに取っている——遅延評価の実装では不要な制約である。

朔日列(各旧暦月の第 1 日)。旧正月が 3 年分——2025-01-29・2026-02-17・2027-02-07——現れる (照合は 95-reference-data.md):

# eval: 2025-01-01..2027-03-01
premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"
  asof:   2026-02-02
  tz:     "Asia/Tokyo"
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12] covering: 2024-12-31..2027-12-31
  lunarStart   = newMoons |> snapTo(day)
  monthNos     = [12, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  lunarMonth   = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNos)
  lunarDayNo   = d => ordinalIn(day, lunarMonth, d)
  rokuyoNo     = d => (lunarMonth(d) + lunarDayNo(d)) mod 6
}
premise Koyomi { calendar-system: Kyureki; tz: "Asia/Tokyo"; wkst: Mon }
@Koyomi
lunarMonth |> first
#=> 2025-01-29 2025-02-28 2025-03-29 2025-04-28 2025-05-27 2025-06-25
#=> 2025-07-25 2025-08-23 2025-09-22 2025-10-21 2025-11-20 2025-12-20
#=> 2026-01-19 2026-02-17 2026-03-19 2026-04-17 2026-05-17 2026-06-15
#=> 2026-07-14 2026-08-13 2026-09-11 2026-10-11 2026-11-09 2026-12-09
#=> 2027-01-08 2027-02-07

閏六月(2025)。月番号 6 の朔日は 2025 年だけ 2 回あり、2 個目(2025-07-25)が閏六月——monthNos の 繰り返しがそのまま窓に現れる。六月は 30 日(6/25〜7/24)・閏六月は 29 日(7/25〜8/22)で、 lunarMonth(d) == 6 の日は 2025 年に計 59 日ある(95-reference-data.md の月表と一致):

# eval: 2025-01-01..2028-01-01
premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"
  asof:   2026-02-02
  tz:     "Asia/Tokyo"
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12] covering: 2024-12-31..2027-12-31
  lunarStart   = newMoons |> snapTo(day)
  monthNos     = [12, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  lunarMonth   = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNos)
  lunarDayNo   = d => ordinalIn(day, lunarMonth, d)
  rokuyoNo     = d => (lunarMonth(d) + lunarDayNo(d)) mod 6
}
premise Koyomi { calendar-system: Kyureki; tz: "Asia/Tokyo"; wkst: Mon }
@Koyomi
lunarMonth |> first |> filter(d => lunarMonth(d) == 6)
#=> 2025-06-25 2025-07-25 2026-07-14 2027-07-04

の射影 kyuMonth(d)(「閏六月」を含む)も同じ窓列で立つ——閏六月の朔日を月名で選ぶ:

# eval: 2025-01-01..2028-01-01
premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"
  asof:   2026-02-02
  tz:     "Asia/Tokyo"
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12] covering: 2024-12-31..2027-12-31
  lunarStart   = newMoons |> snapTo(day)
  monthNames   = ["十二月", "一月", "二月", "三月", "四月", "五月", "六月", "閏六月", "七月", "八月", "九月", "十月", "十一月",
                  "十二月", "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月",
                  "十二月", "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]
  kyuMonth     = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNames)
}
premise Koyomi { calendar-system: Kyureki; tz: "Asia/Tokyo"; wkst: Mon }
@Koyomi
kyuMonth |> first |> filter(d => kyuMonth(d) == "閏六月")
#=> 2025-07-25

旧暦十五日(nth(15))と望(満月)のずれ。暦要項の望 2026 は 1/3・2/2・3/3・4/2・5/2・5/31・6/30・7/29・ 8/28・9/27・10/26・11/24・12/24——年初の 4 回と 5/31 は十五日と同日だが、残る 8 回は望が 1〜2 日遅れる (2 日遅れは 9/27 の 1 回だけ)。「十五夜」は暦の座標(窓の第 15 日)、望は天文事象(データ)で、 同義ではない:

# eval: 2026-01-01..2027-01-01
premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"
  asof:   2026-02-02
  tz:     "Asia/Tokyo"
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12] covering: 2024-12-31..2027-12-31
  lunarStart   = newMoons |> snapTo(day)
  monthNos     = [12, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  lunarMonth   = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNos)
  lunarDayNo   = d => ordinalIn(day, lunarMonth, d)
  rokuyoNo     = d => (lunarMonth(d) + lunarDayNo(d)) mod 6
}
premise Koyomi { calendar-system: Kyureki; tz: "Asia/Tokyo"; wkst: Mon }
@Koyomi
lunarMonth |> nth(15)
#=> 2026-01-03 2026-02-02 2026-03-03 2026-04-02 2026-05-01 2026-05-31 2026-06-29
#=> 2026-07-28 2026-08-27 2026-09-25 2026-10-25 2026-11-23 2026-12-23

大安(rokuyoNo == 0)。同じ旧暦月の中では 6 日ごと、月替わりで位相が飛ぶ——10/8→10/13(旧九月へ)・ 11/6→11/10(旧十月へ)・12/4→12/9(旧十一月へ。朔日 12/9 自身が大安: (11+1) mod 6 = 0)。生成子を everyDay でなく lunarMonth にしているのは §7 (3):

# eval: 2026-10-01..2027-01-01
premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"
  asof:   2026-02-02
  tz:     "Asia/Tokyo"
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12] covering: 2024-12-31..2027-12-31
  lunarStart   = newMoons |> snapTo(day)
  monthNos     = [12, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  lunarMonth   = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNos)
  lunarDayNo   = d => ordinalIn(day, lunarMonth, d)
  rokuyoNo     = d => (lunarMonth(d) + lunarDayNo(d)) mod 6
}
premise Koyomi { calendar-system: Kyureki; tz: "Asia/Tokyo"; wkst: Mon }
@Koyomi
lunarMonth |> filter(d => rokuyoNo(d) == 0)
#=> 2026-10-02 2026-10-08 2026-10-13 2026-10-19 2026-10-25 2026-10-31
#=> 2026-11-06 2026-11-10 2026-11-16 2026-11-22 2026-11-28 2026-12-04
#=> 2026-12-09 2026-12-15 2026-12-21 2026-12-27

旧暦 1/1 は 3 年とも先勝。朔日(第 1 日)のうち先勝のものを取ると、(m + 1) mod 6 == 2 ⟺ m ∈ {1, 7} なので 現れるのは旧一月と旧七月の朔日だけ——旧正月 3 件(1/29・2/17・2/7)がすべて含まれ、「旧暦 1/1 は必ず先勝」 (§5)がデータで立つ。2025-08-23(旧七月の朔日)は §7 (2) の同日競合の日でもある:

# eval: 2025-01-01..2028-01-01
premise Kyureki = Gregorian with {
  source: "eco.mtk.nao.ac.jp/koyomi/yoko"
  asof:   2026-02-02
  tz:     "Asia/Tokyo"
  newMoons = [2024-12-31T07:27,
              2025-01-29T21:36, 2025-02-28T09:45, 2025-03-29T19:58, 2025-04-28T04:31, 2025-05-27T12:02,
              2025-06-25T19:32, 2025-07-25T04:11, 2025-08-23T15:07, 2025-09-22T04:54, 2025-10-21T21:25,
              2025-11-20T15:47, 2025-12-20T10:43, 2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23,
              2026-04-17T20:52, 2026-05-17T05:01, 2026-06-15T11:54, 2026-07-14T18:44, 2026-08-13T02:37,
              2026-09-11T12:27, 2026-10-11T00:50, 2026-11-09T16:02, 2026-12-09T09:52, 2027-01-08T05:24,
              2027-02-07T00:56, 2027-03-08T18:29, 2027-04-07T08:51, 2027-05-06T19:59, 2027-06-05T04:40,
              2027-07-04T12:02, 2027-08-02T19:05, 2027-09-01T02:41, 2027-09-30T11:36, 2027-10-29T22:37,
              2027-11-28T12:24, 2027-12-28T05:12] covering: 2024-12-31..2027-12-31
  lunarStart   = newMoons |> snapTo(day)
  monthNos     = [12, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                  12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  lunarMonth   = day |> segmentBy(lunarStart, edges: drop, empties: error, labels: monthNos)
  lunarDayNo   = d => ordinalIn(day, lunarMonth, d)
  rokuyoNo     = d => (lunarMonth(d) + lunarDayNo(d)) mod 6
}
premise Koyomi { calendar-system: Kyureki; tz: "Asia/Tokyo"; wkst: Mon }
@Koyomi
lunarMonth |> first |> filter(d => rokuyoNo(d) == 2)
#=> 2025-01-29 2025-08-23 2026-02-17 2026-08-13 2027-02-07 2027-08-02

7. 落とし穴

  1. マーカーは snapTo(day) してから segmentBy に渡す(F22・ADR-26)。瞬間のまま渡すと、日の所属は 代表点(日の先頭 00:00)で決まるため朔当日が前の月に落ちる——旧暦の「朔の瞬間を含む日から新しい月」 と逆になる。lunarStart = newMoons |> snapTo(day) の一手が必須。
  2. 2025-08-23 は朔と処暑が同日。瞬間では処暑 5:34 が朔 15:07 より先だが、日単位の月切りでは処暑は 8/23 に始まる月(旧七月)に属する。この帰属が「2025 年の閏月は閏六月(閏七月ではない)」を決めた—— 月切りも中気帰属も日単位の規則であることを明示する必要がある実例(95-reference-data.md 注記)。
  3. データ被覆域の外は「落として註釈」(F61 → ADR-37 で確定)。everyDay |> filter(d => lunarDayNo(d) == 1) のような everyDay 起点も書ける——被覆域外の日は述語評価が範囲外参照になる ため点が落ち、その区間が「範囲外」の評価註釈として結果に並走する(spec §4.10。覆域内の結果は 正確なまま)。テーブル時点が計算範囲を越える形も硬エラーではなくクリップ+実装警告。註釈を読まない 消費者にとっては従来どおり lunarMonth 起点(edges: drop が点列をデータの窓に制限する)が簡明。
  4. monthNos/monthNamesnewMoons と結合した並行リスト——結びは labels: が宣言で錨する (F62 → ADR-39 で確定)。同長(リスト長=窓数 38。覆域基準)は言語が検査する——朔を足してラベルを 足し忘れる/余分に足す、のどちらの方向も評価時の静的エラーで割れる(かつては長い方向が黙って全月番号を ずれさせた)。検査が守るのは長さのみで、同長の位置ずれ(先頭に朔を足しラベルを末尾に足す誤更新)は 通る——中身の照合は旧正月の doctest(§6・lunarMonth(d) == 1 の first)と coincides の閏月検出 (lunarMonth |> first |> filter(p => not coincides(chukiDay, lunarMonth, p))=ADR-38)が分担する。
  5. 窓の月名は labels: が正準(ADR-39)——kyuMonth = day |> segmentBy(lunarStart, …, labels: monthNames) の束縛名射影で任意の日から読める(§1。同長検査も monthNames 側に二重に効く)。 label: 付与式(ADR-34。ラムダは窓の先頭点を受ける・射影時の遅延評価)は labels: に乗らない 計算ラベル用に残る(添字式・条件を含むラベル計算。ADR-30 改訂):

    # 計算ラベルの例(ADR-34): 月名に閏マークを条件で付ける等、リストに乗らない計算だけ label: ラムダ
    kyuMonthC = day |> segmentBy(lunarStart, edges: drop, empties: error,
                                 label: (p => monthNames[epochOrdinal(lunarMonth, p)]))
    

    なお点ラベル(テーブルの labels:)は列の点上でのみ定義される——朔日テーブルに月名列を添えても 月の途中の日からは読めない、という点と窓の対称は変わらない(ADR-30/39)。

  6. データの末端(ADR-37 で確定): covering: は「範囲内は完全」の主張なので列の全要素の包含が 静的検査になる——先頭朔 2024-12-31 を含めるため covering は実端 2024-12-31..2027-12-31 で宣言する (かつての 2025..2027 は静的エラーになる形)。末端側は edges: の発火判定が覆域の端(列の端では ない)——覆域は「2027-12-29〜31 に朔は無い」を保証するので、最終朔 2027-12-28 起点の窓も覆域端まで 確定して張り、旧暦座標は 2027-12-31 まで言える。その先(2028-01-01〜)が「範囲外」の註釈。 2028 年は令和10年暦要項の発表(例年 2 月)を待って newMoonsmonthNos/monthNamescovering:揃えて伸ばす(対更新を忘れれば同長検査が割れて知れる=ADR-39)。

8. スコープ(Kyureki が負わないもの)