日本語 · English

休配日と着日——物流の営業日カレンダーを定義から作る

物流・通販の情報システム部門向けのページ。WMS・TMS・受注システムが参照する「営業日マスタ」「休配日マスタ」を、 年ごとに手で埋めるのではなく、規則と祝日表から生成し、年次更新を再生成と検算で回す人を想定する。言語の仕様は読まなくてよい。

Kairos は WMS・TMS を置き換えない。役割を分ける。どの日が営業日か・何日に着くかを定義から出す係を Kairos に、 受注・在庫・配車はこれまでのシステムに。結果はタブ区切り(TSV)でマスタへ渡す(§マスタへ渡す)。 休配日の正は運送会社の公式告知にある(§上流の権威は上流に)。このページの規則は公開情報の典型で、 会社ごとに違う。

一覧

要求 規則(典型) Kairos
休配日 日曜・祝日・年末年始 12/30〜1/3・お盆 8/13〜8/15 sunday・祝日表・会社の休業日の和
営業日(出荷・配達する日) 休配日でない日 everyDay から休配日を引く
着日 出荷日+N 営業日(近県 1・遠方 2・離島 3 以上) shift(+N, unit: deliveryDay)
受注の締め 営業日の 15 時。以降は翌営業日出荷 at(T15:00)
定期便の集荷 毎週火・金。休配日なら翌営業日 filter と roll(Following)
棚卸 月末最終営業日 within(month) と last
年末年始の帯 12/26〜1/7 を一覧にして配る list --from --to

前文——祝日表と会社の休業日

材料は 3 つ。日曜は規則で、祝日は表で、会社の休業日(年末年始・お盆)も表で持つ。 会社の休業日は年ごとに決まるものなので、規則にせず表に書く。

# 営業日(日祝・年末年始・お盆を除く)
# eval: 2026-01-01..2026-01-11
premise JP {
  calendar-system: Gregorian
  tz: "Asia/Tokyo"
  wkst: Mon
}

@JP
holidays2026 = [2026-01-01, 2026-01-12, 2026-02-11, 2026-02-23, 2026-03-20,
                2026-04-29, 2026-05-03, 2026-05-04, 2026-05-05, 2026-05-06,
                2026-07-20, 2026-08-11, 2026-09-21, 2026-09-22, 2026-09-23,
                2026-10-12, 2026-11-03, 2026-11-23] covering: 2026..2026
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery

deliveryDay
#=> 2026-01-05 2026-01-06 2026-01-07 2026-01-08 2026-01-09 2026-01-10

土曜も休配なら sunday の行を satSun = everyDay |> filter(d => weekday(d) == Sat or weekday(d) == Sun) に替え、 noDelivery の sunday を satSun にする。

以下の例は premise JP と holidays2026 を省いて書く(このサイトの検証では 2026 年の祝日表を持つ標準前提が自動で前置される)。 手元で動かすときは、上の前文を式の上に置く。

休配日と営業日

8 月の休配日。お盆の 3 日と山の日(8/11)、日曜が並ぶ:

# eval: 2026-08-01..2026-09-01
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
noDelivery
#=> 2026-08-02 2026-08-09 2026-08-11 2026-08-13 2026-08-14 2026-08-15 2026-08-16 2026-08-23 2026-08-30

営業日は deliveryDay(everyDay \ noDelivery)。1 年分なら範囲を 2026-01-01..2027-01-01 にする(2026 年は 289 日)。

着日=出荷日+N 営業日

着日は営業日の目盛りで数える。shift(+N, unit: deliveryDay) が「営業日で N つ先」。 ゴールデンウィーク前の 4/30(木)・5/1(金)・5/2(土)に出荷した荷物で、近県(1 営業日):

# eval: 2026-04-27..2026-05-16
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
shipped = [2026-04-30, 2026-05-01, 2026-05-02] covering: 2026..2026
shipped |> shift(+1, unit: deliveryDay)
#=> 2026-05-01 2026-05-02 2026-05-07

遠方(2 営業日)は数字を変えるだけ:

# eval: 2026-04-27..2026-05-16
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
shipped = [2026-04-30, 2026-05-01, 2026-05-02] covering: 2026..2026
shipped |> shift(+2, unit: deliveryDay)
#=> 2026-05-02 2026-05-07 2026-05-08

5/2(土)出荷は近県でも 5/7(木)着——5/3〜5/6 が休配だから。遠方は 5/8。離島は +3。

受注日から出すときは、受注日が休配日なら翌営業日の出荷にしてから数える。roll(Following, on: deliveryDay) を先に置く:

# eval: 2026-04-27..2026-05-16
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
orders = [2026-05-02, 2026-05-03, 2026-05-04] covering: 2026..2026
orders |> roll(Following, on: deliveryDay) |> shift(+1, unit: deliveryDay)
#=> 2026-05-07 2026-05-08

5/2(土)受注は 5/2 出荷で 5/7 着。5/3(日)と 5/4(祝)の受注はどちらも 5/7 出荷で 5/8 着。結果は日付の集合なので、 同じ着日に落ちた 2 件は 1 点になる(件ごとの対応は受注システム側で 1 件ずつ引く)。 shift(unit: deliveryDay) は入力が営業日でないとエラーで止まるので、roll を先に置く順を守る。

受注の締め時刻(15 時)

15 時までの受注は当日出荷、15 時を過ぎた受注は翌営業日出荷。締めは「営業日の 15 時」の点列として書く:

# eval: 2026-04-30..2026-05-09
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
deliveryDay |> at(T15:00)
#=> 2026-04-30T15:00 2026-05-01T15:00 2026-05-02T15:00 2026-05-07T15:00 2026-05-08T15:00

定期便の集荷(毎週火・金・休配日なら翌営業日)

曜日で作って、休配日なら翌営業日へ寄せる。9 月の連休(9/21 敬老の日・9/22 国民の休日・9/23 秋分の日)で:

# eval: 2026-09-14..2026-10-01
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
pickup = everyDay |> filter(d => weekday(d) == Tue or weekday(d) == Fri)
pickup |> roll(Following, on: deliveryDay)
#=> 2026-09-15 2026-09-18 2026-09-24 2026-09-25 2026-09-29

9/22(火)は翌 9/23 も祝日なので 9/24(木)へ。9/25(金)はそのまま。roll は営業日の点を動かさない。

月末の棚卸(月末最終営業日)

# eval: 2026-01-01..2027-01-01
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
deliveryDay |> within(month) |> last
#=> 2026-01-31 2026-02-28 2026-03-31 2026-04-30 2026-05-30 2026-06-30
#=> 2026-07-31 2026-08-31 2026-09-30 2026-10-31 2026-11-30 2026-12-29

土曜が営業日なので 1/31(土)・10/31(土)はそのまま。5 月は 5/31(日)の手前の 5/30(土)。 12 月は 12/30〜31 が休業なので 12/29(火)。

年末年始の帯(12/26〜1/7)

年末に配る「年末年始の営業日のお知らせ」の帯。12/26 から 1/7 までを一覧にする:

# eval: 2026-12-26..2027-01-08
@JP
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31] covering: 2026..2026
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays2026 | closed
deliveryDay = everyDay \ noDelivery
deliveryDay
#=> 2026-12-26 2026-12-28 2026-12-29 2027-01-01 2027-01-02 2027-01-04 2027-01-05 2027-01-06 2027-01-07
#~> 範囲外 2027-01-01..2027-01-08(holidays2026 covering 2026-01-01..2026-12-31)
#~> 範囲外 2027-01-01..2027-01-08(closed covering 2026-01-01..2026-12-31)

12/30・12/31 は休業。2027-01-01 と 01-02 が営業日として出ている——祝日表も休業日の表も 2026 年で尽きているから。 点の下の 2 行がそれを言う(CLI では # ⚠ 範囲外 … の行と、被覆サマリの残走路がマイナスで出る)。 点は出るが、表を知らずに出ている。この帯を配る前に表を延ばす。

表を延ばす=2027 年の行を足し、covering: を 2026..2027 にする:

# 営業日(2027 年まで延ばした表)
# eval: 2026-12-26..2027-01-08
premise JP {
  calendar-system: Gregorian
  tz: "Asia/Tokyo"
  wkst: Mon
}

@JP
holidays = [2026-01-01, 2026-01-12, 2026-02-11, 2026-02-23, 2026-03-20,
            2026-04-29, 2026-05-03, 2026-05-04, 2026-05-05, 2026-05-06,
            2026-07-20, 2026-08-11, 2026-09-21, 2026-09-22, 2026-09-23,
            2026-10-12, 2026-11-03, 2026-11-23,
            2027-01-01, 2027-01-11, 2027-02-11, 2027-02-23, 2027-03-21,
            2027-03-22, 2027-04-29, 2027-05-03, 2027-05-04, 2027-05-05,
            2027-07-19, 2027-08-11, 2027-09-20, 2027-09-23, 2027-10-11,
            2027-11-03, 2027-11-23] covering: 2026..2027
closed = [2026-01-01..2026-01-03, 2026-08-13..2026-08-15, 2026-12-30..2026-12-31,
          2027-01-01..2027-01-03] covering: 2026..2027
sunday = everyDay |> filter(d => weekday(d) == Sun)
noDelivery = sunday | holidays | closed
deliveryDay = everyDay \ noDelivery

deliveryDay
#=> 2026-12-26 2026-12-28 2026-12-29 2027-01-04 2027-01-05 2027-01-06 2027-01-07

註釈が消え、1/4(月)が年始の初営業日になる。表の名前に年を入れない(holidays)と、延ばすたびに式を直さずに済む。 翌年の祝日は内閣府の公示(毎年 2 月)から写す。年次更新の時期・出所・手順は保守の手引きにある。

マスタへ渡す(TSV)

--tsv(1.0.10 から)は、結果を 1 点 1 行のタブ区切りで書き出す。1 つのファイルに本体式を 2 つ並べると expr 列が 1・2 で区別されるので、営業日マスタと休配日マスタを 1 回で出せる。前文の末尾を deliveryDay と noDelivery の 2 行にして:

kairos list --tsv --from 2026-01-01 --to 2027-01-01 --tz Asia/Tokyo delivery.kairos > delivery.tsv

年次更新は、表を延ばして同じコマンドを再実行し、旧マスタと差分を取る。差分が「足した年の行だけ」なら検算は済み。

落とし穴

落とし穴 何が起きるか 対処
会社差 日祝も配達する会社がある。土曜の休配・お盆の日付・年末年始の長さも会社ごとに違う sunday を satSun に、closed の行を公式告知どおりに
表の外 表が尽きた先も点は出る(祝日を知らずに)。⚠ 範囲外 と残走路のマイナスが知らせる 表を延ばす。covering: の終端も
年次更新の忘れ 翌年にかかる範囲を出すたびに ⚠ と残走路のマイナスが出る 毎年 2 月、翌年分を足す(保守の手引き)
shift の入力が休配日 unit: deliveryDay は入力が営業日でないとエラーで止まる roll(Following, on: deliveryDay) を先に
評価範囲の端 shift で範囲の外へ動いた点は出ない(window-clip の警告) 範囲を N 営業日ぶん広げて評価する
roll(Following) と年末 1 年分を出すと 12/29 から ⚠ が立つ(翌営業日が表の外に落ちうるため) 点そのものは正しい。表を延ばせば消える
at と表の外 表の外に落ちた点が at で消え、註釈だけ残る 年をまたぐ前に表を延ばす。表の内側で評価する
--tz を書かない 機械の tz で印字され、日付に時刻が付くことがある --tz Asia/Tokyo。定義の tz と揃える

上流の権威は上流に

ブラウザで試す

前提込みの自己完結形(祝日表と休業日を式の中に持つ)。ブラウザ内で完結し、何も送信しない:

関連

語彙と仕様の所在: