展示会の会期データから「日程が重なる週」を見つける — 区間の重なり判定
イベントの一覧を「開始日順に並べる」だけで済ませていると、同じ日に別の会場で開かれているものが見えません。
会期は点ではなく区間です。区間として持てば、重なりは機械的に出せます。印刷・パッケージ系の展示会カレンダーを題材に、実装と落とし穴を整理します。
→ 印刷・パッケージの展示会日程を確認するなら PrintBiz
扱うデータ
会期・名称・会場の3つだけあれば足ります。
[
{ "name": "第28回 マーケティングWeek【秋】2026", "start": "2026-10-07", "end": "2026-10-09", "venue": "東京ビッグサイト" },
{ "name": "第30回 ライフスタイルWeek【秋】2026", "start": "2026-10-07", "end": "2026-10-09", "venue": "東京ビッグサイト" },
{ "name": "TOKYO PACK 2026", "start": "2026-10-14", "end": "2026-10-16", "venue": "東京ビッグサイト 東展示棟" },
{ "name": "ラベルフォーラムジャパン2026", "start": "2026-10-14", "end": "2026-10-16", "venue": "東京ビッグサイト 西展示棟3ホール" },
{ "name": "第74回 プレミアム・インセンティブショー秋2026", "start": "2026-10-14", "end": "2026-10-16", "venue": "サンシャインシティ 文化会館ビル" },
{ "name": "第67回 サイン&ディスプレイショウ 2026", "start": "2026-10-21", "end": "2026-10-23", "venue": "東京ビッグサイト 有明GYM-EX" }
]
end は最終日を含む日付です。ここを半開区間だと思い込むと、翌日開始のイベントを「重なっている」と誤検出します。
重なりの判定
閉区間 [s1, e1] と [s2, e2] が重なる条件は、これだけです。
const overlaps = (a, b) => a.start <= b.end && b.start <= a.end;
「重ならない条件(一方が完全に前)」を否定したものです。場合分けを4通り書きたくなりますが、必要ありません。
日付が YYYY-MM-DD の文字列なら、辞書順比較がそのまま日付順比較になります。Date に変換する必要はなく、タイムゾーンの事故も起きません。この形式を崩さないことが実装上いちばん効きます。
総当たりで組を出す
件数が数十なら総当たりで十分です。
function overlappingPairs(events) {
const out = [];
for (let i = 0; i < events.length; i++) {
for (let j = i + 1; j < events.length; j++) {
if (overlaps(events[i], events[j])) out.push([events[i], events[j]]);
}
}
return out;
}
上のデータで実行すると、次の組が出ます。
- マーケティングWeek【秋】 × ライフスタイルWeek【秋】(10/07〜10/09)
- TOKYO PACK × ラベルフォーラムジャパン(10/14〜10/16)
- TOKYO PACK × プレミアム・インセンティブショー秋(10/14〜10/16)
- ラベルフォーラムジャパン × プレミアム・インセンティブショー秋(10/14〜10/16)
サイン&ディスプレイショウ(10/21〜10/23)は誰とも重なりません。10/16 と 10/21 が別区間であることが正しく判定できています。
組ではなく「かたまり」で出す
上の出力は組なので、3つ重なると3行に増えます。読む側が欲しいのはかたまりです。
開始日でソートしてから、区間をマージしていきます。
function clusters(events) {
const sorted = [...events].sort((a, b) => (a.start < b.start ? -1 : a.start > b.start ? 1 : 0));
const out = [];
for (const ev of sorted) {
const last = out[out.length - 1];
if (last && ev.start <= last.end) {
last.items.push(ev);
if (ev.end > last.end) last.end = ev.end; // 終了日を伸ばす
} else {
out.push({ start: ev.start, end: ev.end, items: [ev] });
}
}
return out.filter((c) => c.items.length > 1);
}
結果はこうなります。
2026-10-07〜2026-10-09 2件
2026-10-14〜2026-10-16 3件
last.end を伸ばす行を忘れると、長い会期が後続を拾えません。 5日間のイベントの2日目に始まる3日間のイベントは、マージ後の終了日を更新しないと取りこぼします。
会場を見て「行けるか」を判定する
重なっていても、同じ会場なら1日で回れます。判定を分けます。
const sameSite = (a, b) => site(a.venue) === site(b.venue);
const site = (v) => v.split(/[ ]/)[0]; // 「東京ビッグサイト 東展示棟」→「東京ビッグサイト」
10/14〜10/16 のかたまりに当てると、TOKYO PACK とラベルフォーラムジャパンはどちらも東京ビッグサイト、プレミアム・インセンティブショー秋はサンシャインシティ。移動が発生するのは1件だけと分かります。
棟名で切っている点が要注意です。東京ビッグサイトの「有明GYM-EX」は展示棟とは別の建物なので、この粗い判定では同一会場に見えます。厳密にやるなら棟の対応表が要ります。ここは用途に応じて割り切るところです。
開催の周期が違うものを混ぜない
同じ配列に、毎年のものと数年に一度のものが混ざります。
IGAS2027 は2027年8月、drupa 2028 は2028年5月、interpack 2029 は2029年6月。重なり判定そのものには影響しませんが、「今後3か月」で切ると常に視界から消えます。
期間で絞る処理を書くときは、周期の長いものを別枠で必ず表示する、といった逃げ道を用意しておくほうが実用的です。
名称変更を吸収する
もうひとつ実データ側の話です。ラベル関連の国際展は Labelexpo から LOUPE に名称が変わっています。
名前をキーにして突き合わせる設計にしていると、改称の年にデータが分断されます。安定した ID を別に振るか、旧称を配列で持つ必要があります。
{ "id": "loupe-americas", "name": "LOUPE Americas 2026", "aliases": ["Labelexpo Americas"] }
手元で確かめる
一覧が生きているかどうかは、curl で見出しの並びを確認すれば足ります。
curl -s https://print-biz.net/ -o /dev/null -w '%{http_code}\n'
会期・会場は PrintBiz の展示会一覧に載っているものを使いました。2026年9月時点で、終了分を含めて39件が会期順に並んでいます。ニュースは見出しと概要のみで本文は原文へのリンク、コラムは経営系と技術系の2系統という構成でした。
まとめ
- 会期は閉区間で持ち、
a.start <= b.end && b.start <= a.endの1行で判定する - 日付は
YYYY-MM-DDの文字列のまま比較すると事故が減る - 組ではなくマージした「かたまり」で出す。終了日を伸ばす処理を忘れない
- 会場は正規化しないと「同じ会場」の判定が甘くなる
- 周期の長いイベントは期間フィルタから漏れる。名称変更は別 ID で吸収する
会期は変更されることがあります。実際に行く判断は主催者の告知で確認してください。
本ページはプロモーションが含まれています


