はじめに
業務アプリケーションでも、予約管理する機能を作成するときがあります。
その時に予約した日付期間が重複しているかチェックするわけですが、日付期間の重複チェックを複雑に記述される方を見られます。
しかし、これには定石のチェック方法があります。
「比較開始日付 <= 対象終了日付 AND 比較終了日付 >= 対象開始日付」
※条件に、=が成り立っていいかどうかは仕様によります。
別ブログに書いた記事(2008年)ですが別ブログを破棄したので、情報を新たに変更してQiitaに移行しました。
【2019/10/06 追記】
重複するパターンとして対象期間より短いパターン⑦を追加しました。
これによるチェック方法に変更点はありませんが、テストパターンが無いことで誤解を生じさせてしまったみたいです。
また、定石のチェック方法の導き方について書かれた記事がありました。
期間が重複しているかを判定する条件式の導出方法
日付期間の重複チェックパターン
例では日付にしてますが、DateTime型を使ってますので時間でも同様です。
重複するパターン
対象期間 2019/08/05 ~ 2019/09/15
期間① 2019/07/01 ~ 2019/08/31
期間② 2019/08/10 ~ 2019/09/20
期間③ 2019/09/15 ~ 2019/10/10
期間④ 2019/08/01 ~ 2019/09/30
期間⑦ 2019/08/15 ~ 2019/09/05
比較開始日付 <= 対象終了日付 AND 比較終了日付 >= 対象開始日付
重複しないパターン
重複しない以下のパターンでは、定石の条件式は成立しません。
対象期間 2019/08/05 ~ 2019/09/15
期間⑤ 2019/07/01 ~ 2019/08/04
期間⑥ 2019/09/16 ~ 2019/09/30
比較開始日付 > 対象終了日付 OR 比較終了日付 < 対象開始日付
ソースコード
C#でLinqを使用しています。
using System;
using System.Linq;
using System.Data;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
DataTable dtTable = new DataTable();
DataRow drRow;
dtTable.Columns.Add("START_DATE", Type.GetType("System.DateTime"));
dtTable.Columns.Add("END_DATE", Type.GetType("System.DateTime"));
drRow = dtTable.NewRow();
//重複するパターン①~④
drRow["START_DATE"] = DateTime.Parse("2019/07/01");
drRow["END_DATE"] = DateTime.Parse("2019/08/31");
dtTable.Rows.Add(drRow);
drRow = dtTable.NewRow();
drRow["START_DATE"] = DateTime.Parse("2019/08/10");
drRow["END_DATE"] = DateTime.Parse("2019/09/20");
dtTable.Rows.Add(drRow);
drRow = dtTable.NewRow();
drRow["START_DATE"] = DateTime.Parse("2019/09/15");
drRow["END_DATE"] = DateTime.Parse("2019/10/10");
dtTable.Rows.Add(drRow);
drRow = dtTable.NewRow();
drRow["START_DATE"] = DateTime.Parse("2019/08/01");
drRow["END_DATE"] = DateTime.Parse("2019/09/30");
dtTable.Rows.Add(drRow);
//重複するパターン⑦
drRow = dtTable.NewRow();
drRow["START_DATE"] = DateTime.Parse("2019/08/15");
drRow["END_DATE"] = DateTime.Parse("2019/09/05");
dtTable.Rows.Add(drRow);
//重複しないパターン⑤~⑥
drRow = dtTable.NewRow();
drRow["START_DATE"] = DateTime.Parse("2019/07/01");
drRow["END_DATE"] = DateTime.Parse("2019/08/04");
dtTable.Rows.Add(drRow);
drRow = dtTable.NewRow();
drRow["START_DATE"] = DateTime.Parse("2019/09/16");
drRow["END_DATE"] = DateTime.Parse("2019/09/30");
dtTable.Rows.Add(drRow);
//対象期間
DateTime startdate = DateTime.Parse("2019/08/05");
DateTime enddate = DateTime.Parse("2019/09/15");
//重複している場合の抽出条件
//比較開始日付 <= 対象終了日付 AND 比較終了日付 >= 対象開始日付
var query = from x in dtTable.AsEnumerable()
where x.Field<DateTime>("START_DATE") <= enddate && x.Field<DateTime>("END_DATE") >= startdate
select x;
int count = query.Count(); //7件中の5件抽出
if (count > 0)
Console.WriteLine(string.Format("{0}件の期間が重複しています。", count));
//重複していない場合の抽出条件
//比較開始日付 > 対象終了日付 OR 比較終了日付 < 対象開始日付
var query2 = from x in dtTable.AsEnumerable()
where x.Field<DateTime>("START_DATE") > enddate || x.Field<DateTime>("END_DATE") < startdate
select x;
int count2 = query2.Count(); //7件中の2件抽出
if (count2 > 0)
Console.WriteLine(string.Format("{0}件の期間が重複していません。", count2));
}
}
}