Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从两组日期范围C中查找间隔日期范围#_C#_Sql_Linq_Datetime_Collections - Fatal编程技术网

C# 从两组日期范围C中查找间隔日期范围#

C# 从两组日期范围C中查找间隔日期范围#,c#,sql,linq,datetime,collections,C#,Sql,Linq,Datetime,Collections,我有基准日期范围和测试日期范围。我需要得到基准和测试之间的间隙,这意味着缺少基准中但不在测试中的日期范围。最好的方法是什么 Base Date Ranges 1/1/2012 1/10/2012 1/11/2012 1/25/2012 Test Date Ranges 1/2/2012 1/7/2012 1/8/2012 1/9/2012 1/15/2012 1/30/2012 输出: Missing Date Ranges that are in Base bu

我有基准日期范围和测试日期范围。我需要得到基准和测试之间的间隙,这意味着缺少基准中但不在测试中的日期范围。最好的方法是什么

Base Date Ranges
1/1/2012    1/10/2012
1/11/2012   1/25/2012


Test Date Ranges
1/2/2012    1/7/2012
1/8/2012    1/9/2012
1/15/2012   1/30/2012
输出:

Missing Date Ranges that are in Base but not in Test 
1/1/2012    1/2/2012
1/7/2012    1/8/2012
1/9/2012    1/10/2012
1/11/2012   1/15/2012
到目前为止我试过这个

   static void Main(string[] args)
    {


        List<DateRanges> aDateRanges = new List<DateRanges>();
        List<DateRanges> bDateRanges = new List<DateRanges>();

        aDateRanges.Add(new DateRanges(new DateTime(2012, 1, 1), new DateTime(2012, 1, 10)));
        aDateRanges.Add(new DateRanges(new DateTime(2012, 1, 11), new DateTime(2012, 1, 25)));


        bDateRanges.Add(new DateRanges(new DateTime(2012, 1, 2), new DateTime(2012, 1, 7)));
        bDateRanges.Add(new DateRanges(new DateTime(2012, 1, 8), new DateTime(2012, 1, 9)));
        bDateRanges.Add(new DateRanges(new DateTime(2012, 1, 15), new DateTime(2012, 1, 30)));

        DisplayDateRanges(GetGaps(aDateRanges, bDateRanges, 0), "Final Gap Fill");
        Console.WriteLine("Completed");
        Console.Read();
    }

    public class DateRanges
    {
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        public DateRanges(DateTime Start, DateTime End)
        {
            StartDate = Start;
            EndDate = End;
        }
    }

    public static void DisplayDateRanges(List<DateRanges> dateRanges, string title)
    {
        Console.WriteLine("************************{0}****************************", title);
        Console.WriteLine(Environment.NewLine + "New Recursion");
        foreach (DateRanges br in dateRanges)
        {
            Console.WriteLine("Start Date {0}   End Date {1}", br.StartDate, br.EndDate);
        }

    }

    public static List<DateRanges> GetGaps(List<DateRanges> aDateRanges, List<DateRanges> bDateRanges, int recursionlevel)
    {
        List<DateRanges> gapFill = new List<DateRanges>();
        List<DateRanges> gapFillTemp = new List<DateRanges>();
        List<DateRanges> bDateRangesTemp = new List<DateRanges>(bDateRanges);
        Console.WriteLine(Environment.NewLine + "+++++++++++++++++++++++++++++++++++++++++Recursion Level Id {0} +++++++++++++++++++++++++++++++++++++++++", recursionlevel);
        DisplayDateRanges(aDateRanges, " A Date Ranges ");
        DisplayDateRanges(bDateRanges, " B Date Ranges ");

        foreach (DateRanges br in bDateRanges)
        {
            if (br.StartDate == br.EndDate)
                return gapFill;
            foreach (DateRanges ar in aDateRanges)
            {
                if (ar.StartDate == ar.EndDate)
                    return gapFill;
                if (br.StartDate == ar.StartDate && br.EndDate == ar.EndDate)
                    continue;
                else if (br.StartDate >= ar.StartDate && br.EndDate <= ar.EndDate)
                {
                    gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(ar.StartDate, br.StartDate) }, bDateRangesTemp, recursionlevel + 1));
                    if (gapFillTemp.Count == 0)
                    {
                        //gapFillTemp.Add(new DateRanges(ar.StartDate, br.StartDate));
                    }
                    bDateRangesTemp.AddRange(gapFillTemp);
                    gapFill.AddRange(gapFillTemp);
                    gapFillTemp.Clear();

                    gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(br.EndDate, ar.EndDate) }, bDateRangesTemp, recursionlevel + 1));
                    if (gapFillTemp.Count == 0)
                    {
                       // gapFillTemp.Add(new DateRanges(br.EndDate, ar.EndDate));
                    }
                    bDateRangesTemp.AddRange(gapFillTemp);
                    gapFill.AddRange(gapFillTemp);
                    gapFillTemp.Clear();
                }
                else if (br.StartDate < ar.EndDate && br.EndDate >= ar.EndDate)
                {
                    gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(ar.StartDate, br.StartDate) }, bDateRangesTemp, recursionlevel + 1));
                    if (gapFillTemp.Count == 0)
                    {
                        //gapFillTemp.Add(new DateRanges(ar.StartDate, br.StartDate));
                    }
                    bDateRangesTemp.AddRange(gapFillTemp);
                    gapFill.AddRange(gapFillTemp);
                    gapFillTemp.Clear();
                }

                else if (ar.StartDate >= br.StartDate && ar.StartDate < br.EndDate)
                {
                    gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(br.EndDate, ar.EndDate) }, bDateRangesTemp, recursionlevel + 1));
                    if (gapFillTemp.Count == 0)
                    {
                       // gapFillTemp.Add(new DateRanges(br.EndDate, ar.EndDate));
                    }
                    bDateRangesTemp.AddRange(gapFillTemp);
                    gapFill.AddRange(gapFillTemp);
                    gapFillTemp.Clear();
                }

                else if (ar.StartDate >= br.StartDate && ar.EndDate <= br.EndDate)
                {
                    //     AS----AE
                    //  BS----------BE           
                    //Do Nothing

                }
                else
                {
                    if (AllowedToAdd(bDateRangesTemp, new DateRanges(ar.StartDate, ar.EndDate)))
                    {
                        bDateRangesTemp.Add(new DateRanges(ar.StartDate, ar.EndDate));
                        gapFill.Add(new DateRanges(ar.StartDate, ar.EndDate));
                    }
                }

            }



        }
        return gapFill;
    }


    static bool AllowedToAdd(List<DateRanges> bDateRanges, DateRanges newItem)
    {
        return !bDateRanges.Any(m =>
            (m.StartDate < newItem.StartDate &&
             newItem.StartDate < (m.EndDate))
            ||
            (m.StartDate < (newItem.EndDate) &&
             (newItem.EndDate) <= (m.EndDate))
            ||
            (newItem.StartDate < m.StartDate &&
             m.StartDate < (newItem.EndDate))
            ||
            (newItem.StartDate < (m.EndDate) &&
             (m.EndDate) <= (newItem.EndDate))
            );
    }
static void Main(字符串[]args)
{
列表aDateRanges=新列表();
List bDateRanges=新列表();
Add(新的日期范围(新的日期时间(2012,1,1),新的日期时间(2012,1,10));
添加(新的日期范围(新的日期时间(2012,1,11),新的日期时间(2012,1,25));
添加(新的日期范围(新的日期时间(2012,1,2),新的日期时间(2012,1,7));
添加(新的日期范围(新的日期时间(2012,1,8),新的日期时间(2012,1,9));
添加(新的日期范围(新的日期时间(2012,1,15),新的日期时间(2012,1,30));
显示日期范围(GetGaps(aDateRanges,bDateRanges,0),“最终间隙填充”);
控制台。写入线(“已完成”);
Console.Read();
}
公共类日期范围
{
公共日期时间起始日期{get;set;}
公共日期时间结束日期{get;set;}
公共日期范围(日期时间开始、日期时间结束)
{
开始日期=开始;
结束日期=结束;
}
}
公共静态void DisplayDateRanges(列出日期范围、字符串标题)
{
Console.WriteLine(“***************************{0}*************************************************”,标题);
Console.WriteLine(Environment.NewLine+“新递归”);
foreach(DateRanges br(DateRanges中的DateRanges br)
{
WriteLine(“开始日期{0}结束日期{1}”,br.StartDate,br.EndDate);
}
}
公共静态列表GetGaps(列表aDateRanges、列表bDateRanges、int recursionlevel)
{
List gapFill=新列表();
List gapFillTemp=新列表();
列表bDateRangesTemp=新列表(bDateRanges);
Console.WriteLine(Environment.NewLine++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++;
显示日期范围(aDateRanges,“A日期范围”);
显示日期范围(B数据范围,“B日期范围”);
foreach(日期范围br,以bDateRanges为单位)
{
如果(br.StartDate==br.EndDate)
回灌;
foreach(aDateRanges中的日期范围)
{
if(ar.StartDate==ar.EndDate)
回灌;
如果(br.StartDate==ar.StartDate&&br.EndDate==ar.EndDate)
继续;
否则如果(br.StartDate>=ar.StartDate&&br.EndDate=ar.EndDate)
{
gapFillTemp.AddRange(GetGaps(新列表{new DateRanges(ar.StartDate,br.StartDate)},bDateRangesTemp,递归级别+1));
如果(gapFillTemp.Count==0)
{
//gapFillTemp.Add(新的日期范围(ar.StartDate,br.StartDate));
}
bDateRangesTemp.AddRange(间隙填充温度);
gapFill.AddRange(gapFillTemp);
间隙填充温度清除();
}
否则如果(ar.StartDate>=br.StartDate&&ar.StartDate=br.StartDate&&ar.EndDate
(m.StartDate(newItem.EndDate)以下代码满足问题的给定约束:

单元测试
static void Main(字符串[]args)
{
IEnumerable _base=new[]{new DateRange(){Start=DateTime.Parse(“1/1/2012”),End=DateTime.Parse(“1/10/2012”)},
new DateRange(){Start=DateTime.Parse(“1/11/2012”),End=DateTime.Parse(“1/25/2012”)};
IEnumerable _test=new[]{new DateRange(){Start=DateTime.Parse(“1/2/2012”),End=DateTime.Parse(“1/7/2012”)},
new DateRange(){Start=DateTime.Parse(“1/8/2012”),End=DateTime.Parse(“1/9/2012”)},
new DateRange(){Start=DateTime.Parse(“1/15/2012”),End=DateTime.Parse(“1/30/2012”)};
IEnumerable _theoryalgaps=new[]{new DateRange(){Start=DateTime.Parse(“1/1/2012”),End=DateTime.Parse(“1/2/2012”)},
new DateRange(){Start=DateTime.Parse(“1/7/2012”),End=DateTime.Parse(“1/8/2012”)},
new DateRange(){Start=DateTime.Parse(“1/9/2012”),End=DateTime.Parse(“1/10/2012”)},
new DateRange(){Start=DateTime.Parse(“1/11/2012”),End=DateTime.Parse(“1/15/2012”)};
var gapsInTestNotInBase=FindGaps(_base,_test);
Assert(Enumerable.SequenceEqual(_theoryalgaps,gapsInTestNotInBase));
}
FindGaps法
公共静态IEnumerable FindGaps(IEnumerable baseCollection、IEnumerable testCollection)
{
var allBaseDates=baseCollection.SelectMany(o=>o.GetDiscreetDates())
.Distinct()
.OrderBy(o=>o.Ticks);
var missingInTest=(从allBaseDates中的d开始)
设inRange=testCollection.Any(o=>d.IsInRange(o))
哪里
    static void Main(string[] args)
    {
        IEnumerable<DateRange> _base = new[] { new DateRange() { Start = DateTime.Parse("1/1/2012"), End = DateTime.Parse("1/10/2012")},
                                               new DateRange() { Start = DateTime.Parse("1/11/2012"), End = DateTime.Parse("1/25/2012")} };

        IEnumerable<DateRange> _test = new[] { new DateRange() { Start = DateTime.Parse("1/2/2012"), End = DateTime.Parse("1/7/2012")},
                                               new DateRange() { Start = DateTime.Parse("1/8/2012"), End = DateTime.Parse("1/9/2012")},
                                               new DateRange() { Start = DateTime.Parse("1/15/2012"), End = DateTime.Parse("1/30/2012")} };

        IEnumerable<DateRange> _theoreticalGaps = new[] { new DateRange() { Start = DateTime.Parse("1/1/2012"), End = DateTime.Parse("1/2/2012")},
                                               new DateRange() { Start = DateTime.Parse("1/7/2012"), End = DateTime.Parse("1/8/2012")},
                                               new DateRange() { Start = DateTime.Parse("1/9/2012"), End = DateTime.Parse("1/10/2012")},
                                               new DateRange() { Start = DateTime.Parse("1/11/2012"), End = DateTime.Parse("1/15/2012")} };


        var gapsInTestNotInBase = FindGaps(_base, _test);

        Debug.Assert(Enumerable.SequenceEqual(_theoreticalGaps, gapsInTestNotInBase));
    }
    public static IEnumerable<DateRange> FindGaps(IEnumerable<DateRange> baseCollection, IEnumerable<DateRange> testCollection)
    {
        var allBaseDates = baseCollection.SelectMany(o => o.GetDiscreetDates())
            .Distinct()
            .OrderBy(o => o.Ticks);

        var missingInTest = (from d in allBaseDates
                             let inRange = testCollection.Any(o => d.IsInRange(o))
                             where !inRange
                             select d).ToArray();

        var gaps = missingInTest.Select(o => new DateRange() { Start = o, End = o.AddDays(1) });

        gaps = gaps.GroupConsecutive();

        return gaps;

    }
public class DateRange
{
    protected bool Equals(DateRange other)
    {
        return Start.Equals(other.Start) && End.Equals(other.End);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (Start.GetHashCode()*397) ^ End.GetHashCode();
        }
    }

    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public IEnumerable<DateTime> GetDiscreetDates()
    {
        //Start is not allowed to equal end.
        if (Start.Date == End.Date)
            throw new ArgumentException("Start cannot equal end.");

        var output = new List<DateTime>();

        var current = Start.Date;

        while (current < End.Date) {
            output.Add(current);
            current = current.AddDays(1);
        }

        return output;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((DateRange) obj);
    }
}
public static class Extensions
{
    public static bool IsInRange(this DateTime testDate, DateRange range)
    {
        return range.Start <= testDate && range.End > testDate;
    }

    public static IEnumerable<DateRange> GroupConsecutive(this IEnumerable<DateRange> input)
    {
        var current = input.ToArray();
        var nextIndex = 0;

        //uses lookahead to figure out if gaps are consecutive.
        for (int i = 0; i < current.Length - 1; i++) {

            //If the next range is consecutive to the current, skip;
            if (!current[i].End.IsInRange(current[i + 1])) {
                yield return new DateRange()
                               {
                                   Start = current[nextIndex].Start,
                                   End = current[i].End
                               };
                nextIndex = i + 1;
            }
        }

        //If the last elements were consecutive, pull out the final item.
        if (nextIndex != current.Length) {
            yield return new DateRange()
            {
                Start = current[nextIndex].Start,
                End = current[current.Length - 1].End
            };
        }
    }
}
public static class DateRangeEnumerable
{
    public static IEnumerable<DateTime> GetDates(this IEnumerable<DateRange> source)
    {
        var sortedSource = source.OrderBy(r => r.From);

        foreach (var range in sortedSource)
        {
            var d = range.From;
            while (d < range.To)
            {
                yield return d;
                d = d.AddDays(1);
            }
        }
    }

    public static IEnumerable<DateRange> GetRanges(this IEnumerable<DateTime> source)
    {
        var sortedSource = source.OrderBy(d => d);
        var enumerator = sortedSource.GetEnumerator();

        if (!enumerator.MoveNext())
            yield break;

        DateTime from = enumerator.Current;
        DateTime prev = from;

        while (true)
        {
            while (true)
            {
                if (enumerator.MoveNext())
                {
                    if (enumerator.Current == prev.AddDays(1))
                        prev = enumerator.Current;
                    else
                        break;
                }
                else
                {
                    yield return new DateRange() { From = from, To = prev.AddDays(1) };
                    yield break;
                }

            }

            yield return new DateRange() { From = from, To = prev.AddDays(1) };

            from = enumerator.Current;
            prev = enumerator.Current;
        }
    }
}
var missing = BaseRanges.GetDates().Except(TestRanges.GetDates());
var ranges = missing.GetRanges();
    List<DateRanges> aDateRanges = new List<DateRanges>();
    List<DateRanges> bDateRanges = new List<DateRanges>();

    aDateRanges.Add(new DateRanges(new DateTime(2012, 1, 1), new DateTime(2012, 1, 10)));
    aDateRanges.Add(new DateRanges(new DateTime(2012, 1, 11), new DateTime(2012, 1, 25)));


    bDateRanges.Add(new DateRanges(new DateTime(2012, 1, 2), new DateTime(2012, 1, 7)));
    bDateRanges.Add(new DateRanges(new DateTime(2012, 1, 8), new DateTime(2012, 1, 9)));
    bDateRanges.Add(new DateRanges(new DateTime(2012, 1, 15), new DateTime(2012, 1, 30)));

    DisplayDateRanges(GetGaps(aDateRanges, bDateRanges, 0), "Final Gap Fill");
    Console.WriteLine("Completed");
    Console.Read();
}

public class DateRanges
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public DateRanges(DateTime Start, DateTime End)
    {
        StartDate = Start;
        EndDate = End;
    }
}

public static void DisplayDateRanges(List<DateRanges> dateRanges, string title)
{
    Console.WriteLine("************************{0}****************************", title);
    Console.WriteLine(Environment.NewLine + "New Recursion");
    foreach (DateRanges br in dateRanges)
    {
        Console.WriteLine("Start Date {0}   End Date {1}", br.StartDate, br.EndDate);
    }

}

public static List<DateRanges> GetGaps(List<DateRanges> aDateRanges, List<DateRanges> bDateRanges, int recursionlevel)
{
    List<DateRanges> gapFill = new List<DateRanges>();
    List<DateRanges> gapFillTemp = new List<DateRanges>();
    List<DateRanges> bDateRangesTemp = new List<DateRanges>(bDateRanges);
    Console.WriteLine(Environment.NewLine + "+++++++++++++++++++++++++++++++++++++++++Recursion Level Id {0} +++++++++++++++++++++++++++++++++++++++++", recursionlevel);
    DisplayDateRanges(aDateRanges, " A Date Ranges ");
    DisplayDateRanges(bDateRanges, " B Date Ranges ");

    foreach (DateRanges br in bDateRanges)
    {
        if (br.StartDate == br.EndDate)
            return gapFill;
        foreach (DateRanges ar in aDateRanges)
        {
            if (ar.StartDate == ar.EndDate)
                return gapFill;
            if (br.StartDate == ar.StartDate && br.EndDate == ar.EndDate)
                continue;
            else if (br.StartDate >= ar.StartDate && br.EndDate <= ar.EndDate)
            {
                gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(ar.StartDate, br.StartDate) }, bDateRangesTemp, recursionlevel + 1));
                if (gapFillTemp.Count == 0)
                {
                    //gapFillTemp.Add(new DateRanges(ar.StartDate, br.StartDate));
                }
                bDateRangesTemp.AddRange(gapFillTemp);
                gapFill.AddRange(gapFillTemp);
                gapFillTemp.Clear();

                gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(br.EndDate, ar.EndDate) }, bDateRangesTemp, recursionlevel + 1));
                if (gapFillTemp.Count == 0)
                {
                   // gapFillTemp.Add(new DateRanges(br.EndDate, ar.EndDate));
                }
                bDateRangesTemp.AddRange(gapFillTemp);
                gapFill.AddRange(gapFillTemp);
                gapFillTemp.Clear();
            }
            else if (br.StartDate < ar.EndDate && br.EndDate >= ar.EndDate)
            {
                gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(ar.StartDate, br.StartDate) }, bDateRangesTemp, recursionlevel + 1));
                if (gapFillTemp.Count == 0)
                {
                    //gapFillTemp.Add(new DateRanges(ar.StartDate, br.StartDate));
                }
                bDateRangesTemp.AddRange(gapFillTemp);
                gapFill.AddRange(gapFillTemp);
                gapFillTemp.Clear();
            }

            else if (ar.StartDate >= br.StartDate && ar.StartDate < br.EndDate)
            {
                gapFillTemp.AddRange(GetGaps(new List<DateRanges> { new DateRanges(br.EndDate, ar.EndDate) }, bDateRangesTemp, recursionlevel + 1));
                if (gapFillTemp.Count == 0)
                {
                   // gapFillTemp.Add(new DateRanges(br.EndDate, ar.EndDate));
                }
                bDateRangesTemp.AddRange(gapFillTemp);
                gapFill.AddRange(gapFillTemp);
                gapFillTemp.Clear();
            }

            else if (ar.StartDate >= br.StartDate && ar.EndDate <= br.EndDate)
            {
                //     AS----AE
                //  BS----------BE           
                //Do Nothing

            }
            else
            {
                if (AllowedToAdd(bDateRangesTemp, new DateRanges(ar.StartDate, ar.EndDate)))
                {
                    bDateRangesTemp.Add(new DateRanges(ar.StartDate, ar.EndDate));
                    gapFill.Add(new DateRanges(ar.StartDate, ar.EndDate));
                }
            }

        }



    }
    return gapFill;
}


static bool AllowedToAdd(List<DateRanges> bDateRanges, DateRanges newItem)
{
    return !bDateRanges.Any(m =>
        (m.StartDate < newItem.StartDate &&
         newItem.StartDate < (m.EndDate))
        ||
        (m.StartDate < (newItem.EndDate) &&
         (newItem.EndDate) <= (m.EndDate))
        ||
        (newItem.StartDate < m.StartDate &&
         m.StartDate < (newItem.EndDate))
        ||
        (newItem.StartDate < (m.EndDate) &&
         (m.EndDate) <= (newItem.EndDate))
        );
}
// ----------------------------------------------------------------------
public void GapFinder()
{
  // base periods
  TimePeriodCollection basePeriods = new TimePeriodCollection();
  basePeriods.Add( new TimeRange( new DateTime( 2012, 1, 1 ), new DateTime( 2012, 1, 10 ) ) );
  basePeriods.Add( new TimeRange( new DateTime( 2012, 1, 11 ), new DateTime( 2012, 1, 25 ) ) );
  ITimePeriodCollection combinedBasePeriods = new TimePeriodCombiner<TimeRange>().CombinePeriods( basePeriods );

  // test periods
  TimePeriodCollection testPeriods = new TimePeriodCollection();
  testPeriods.Add( new TimeRange( new DateTime( 2012, 1, 2 ), new DateTime( 2012, 1, 7 ) ) );
  testPeriods.Add( new TimeRange( new DateTime( 2012, 1, 8 ), new DateTime( 2012, 1, 9 ) ) );
  testPeriods.Add( new TimeRange( new DateTime( 2012, 1, 15 ), new DateTime( 2012, 1, 30 ) ) );
  ITimePeriodCollection combinedTestPeriods = new TimePeriodCombiner<TimeRange>().CombinePeriods( testPeriods );

  // gaps
  TimePeriodCollection gaps = new TimePeriodCollection();
  foreach ( ITimePeriod basePeriod in combinedBasePeriods )
  {
    gaps.AddAll( new TimeGapCalculator<TimeRange>().GetGaps( combinedTestPeriods, basePeriod ) );
  }
  foreach ( ITimePeriod gap in gaps )
  {
    Console.WriteLine( "Gap: " + gap );
  }
} // GapFinder