Search code examples
c#vb.netlinqdate-range

Possible date ranges from a list of date range VB.Net or C#


I wanted to get of possible date ranges from a list of data range. Ex:

  1. Below date ranges (startdate, enddate)
    2021-01-01 00:00:00, 2021-01-13 23:59:59
    2021-01-07 00:00:00, 2021-02-03 23:59:59

will output 3 list as below
2021-01-01 00:00:00, 2021-01-06 23:59:59
2021-01-07 00:00:00, 2021-01-13 23:59:59
2021-01-14 00:00:00, 2021-02-03 23:59:59

  1. Below date ranges (startdate, enddate)
    2021-01-01 00:00:00, 2021-01-13 23:59:59
    2021-01-02 00:00:00, 2021-01-03 23:59:59

will output 3 list as below
2021-01-01 00:00:00, 2021-01-01 23:59:59
2021-01-02 00:00:00, 2021-01-03 23:59:59
2021-01-04 00:00:00, 2021-01-13 23:59:59

  1. Below 2 date range in a list (startdate, enddate)
    2021-01-10 00:00:00, 2021-01-30 23:59:59
    2021-02-13 00:00:00, 2021-02-26 23:59:59

will output the same 2 records are there is no overlap.

What i tried is, i got the starting date and ending date of each of the list item. Then sort it and then create a new list tuple of dates with 1st and 2nd in the list

Dim lstDateRanges As New List(Of Tuple(Of Date, Date))
Dim lstDates As New List(Of Date)
Dim lstNewDateRanges As New List(Of Tuple(Of Date, Date))
lstDateRanges.Add(Tuple.Create(CDate("2021-01-01 00:00:00"), CDate("2021-01-13 23:59:59")))
lstDateRanges.Add(Tuple.Create(CDate("2021-01-02 00:00:00"), CDate("2021-01-03 23:59:59")))

For Each dDate In lstDateRanges
    lstDates.Add(dDate.Item1)
    lstDates.Add(dDate.Item2)
Next

lstDates.Sort()

For i As Int32 = 0 To lstDates.Count - 2
    If lstDates(i) <> lstDates(i + 1) Then 'ignore the same starting and ending dates
        lstNewDateRanges.Add(Tuple.Create(lstDates(i), lstDates(i + 1).Date.AddSeconds(-1)))
    End If
Next

This does not work correctly though. I feel the approach i am taking is not right.

Any help would be really appreciated.


Solution

  • Dim lstDateRanges As New List(Of Tuple(Of Date, Date))
            Dim lstDates As New List(Of Date)
            Dim lstNewDateRanges As New List(Of Tuple(Of Date, Date))
    
            lstDateRanges.Add(Tuple.Create(CDate("2021-01-01"), CDate("2021-01-13")))
            lstDateRanges.Add(Tuple.Create(CDate("2021-01-02"), CDate("2021-01-03")))
    
            '2nd test scenario
            'lstDateRanges.Add(Tuple.Create(CDate("2021-01-01"), CDate("2021-01-13")))
            'lstDateRanges.Add(Tuple.Create(CDate("2021-01-07"), CDate("2021-02-03")))
    
            '3nd test scenario
            'lstDateRanges.Add(Tuple.Create(CDate("2021-01-01"), CDate("2021-01-13")))
            'lstDateRanges.Add(Tuple.Create(CDate("2021-01-15"), CDate("2021-02-03")))
    
            '4nd test scenario
            'lstDateRanges.Add(Tuple.Create(CDate("2021-01-01"), CDate("2021-01-07")))
            'lstDateRanges.Add(Tuple.Create(CDate("2021-01-01"), CDate("2021-01-15")))
    
            For Each dDate In lstDateRanges
                lstDates.Add(dDate.Item1)
                lstDates.Add(dDate.Item2)
            Next
    
            lstDates.Sort()
           
            For i As Int32 = 0 To lstDates.Count - 2
                If lstDates(i) <> lstDates(i + 1) Then 'ignore the same starting and ending dates
                    lstNewDateRanges.Add(Tuple.Create(lstDates(i).Date, lstDates(i + 1).Date.AddDays(1).AddSeconds(-1)))
                End If
            Next
    
            For Each newRange In lstNewDateRanges.ToList
                Dim bOverlapAny = False
                For Each oldRange In lstDateRanges
                    If DoDateRangesOverlap(newRange.Item1.Date.AddSeconds(1), newRange.Item2.Date.AddSeconds(-1), oldRange.Item1.Date, oldRange.Item2.Date) Then
                        bOverlapAny = True
                        Exit For
                    End If
                Next
                If Not bOverlapAny Then lstNewDateRanges.Remove(newRange)
            Next