LoginSignup
180
153

More than 3 years have passed since last update.

日付期間の重複チェック

Last updated at Posted at 2016-07-03

はじめに

業務アプリケーションでも、予約管理する機能を作成するときがあります。
その時に予約した日付期間が重複しているかチェックするわけですが、日付期間の重複チェックを複雑に記述される方を見られます。

しかし、これには定石のチェック方法があります。
「比較開始日付 <= 対象終了日付 AND 比較終了日付 >= 対象開始日付」
※条件に、=が成り立っていいかどうかは仕様によります。

別ブログに書いた記事(2008年)ですが別ブログを破棄したので、情報を新たに変更してQiitaに移行しました。

【2019/10/06 追記】
重複するパターンとして対象期間より短いパターン⑦を追加しました。
これによるチェック方法に変更点はありませんが、テストパターンが無いことで誤解を生じさせてしまったみたいです。

また、定石のチェック方法の導き方について書かれた記事がありました。
期間が重複しているかを判定する条件式の導出方法

日付期間の重複チェックパターン

例では日付にしてますが、DateTime型を使ってますので時間でも同様です。

重複するパターン

重複5.png

対象期間 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 比較終了日付 >= 対象開始日付

重複しないパターン

重複しない以下のパターンでは、定石の条件式は成立しません。
重複無し2.png
対象期間 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));
        }
    }
}

参考

180
153
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
180
153