2010-08-02 6 views
8

Próbuję znaleźć brakujące daty między dwiema zmiennymi DateTime dla kolekcji DateTimes.Znajdź brakujące daty dla danego zakresu

Na przykład.

Collection 
2010-01-01 
2010-01-02 
2010-01-03 
2010-01-05 

DateRange 
2010-01-01 -> 2010-01-06 

dałby mi List<DateTime> z

2010-01-04 
2010-01-06 

mogę myśleć kilka było wdrożenie to jednak nic czysty i prosty

Jakieś pomysły?

Odpowiedz

16

mogę myśleć na wiele sposobów realizacji tego np

DateTime[] col = { new DateTime(2010, 1, 1), 
        new DateTime(2010, 1, 2), 
        new DateTime(2010, 1, 3), 
        new DateTime(2010, 1, 5)}; 

var start = new DateTime(2010, 1, 1); 
var end = new DateTime(2010, 1, 6); 

var range = Enumerable.Range(0, (int)(end - start).TotalDays + 1) 
         .Select(i => start.AddDays(i)); 

var missing = range.Except(col); 

I można umieścić rząd-rzeczy w przedłużenie-Metoda

public static class extensions 
{ 
    public static IEnumerable<DateTime> Range(this DateTime startDate, DateTime endDate) 
    { 
     return Enumerable.Range(0, (int)(endDate - startDate).TotalDays + 1) 
         .Select(i => startDate.AddDays(i)); 
    } 
} 

to byłoby być po prostu

DateTime[] col = { new DateTime(2010, 1, 1), 
        new DateTime(2010, 1, 2), 
        new DateTime(2010, 1, 3), 
        new DateTime(2010, 1, 5)}; 

var start = new DateTime(2010, 1, 1); 
var end = new DateTime(2010, 1, 6); 
var missing = start.Range(end).Except(col); 

Ale może nie jest to high-performance-rozwiązanie :-)

+0

To jest podobne do tego, o czym myślałem, z wyjątkiem użycia pętli for do rozbudowy mojego zasięgu. Po prostu nie podobał mi się pomysł budowania listy dni za każdym razem, ponieważ muszę robić to cicho. –

+1

+1 Dobre wykorzystanie zasięgu. – Thomas

+0

Tak, sprytne wykorzystanie zakresu;) –

2

W zależności od tego, czego dokładnie szukasz i rozmiarów zestawów danych. Prostym sposobem byłoby załadowanie dat do kolekcji, a następnie użycie prostej pętli. Dodam tutaj przykładowy kod w ciągu sekundy.

DateTime currentDate = new DateTime(2010, 1, 1); 
DateTime endDate = new DateTime(2010, 1, 6); 
List<DateTime> existingDates = new List<DateTime>; //You fill with values 
List<DateTime> missingDates = new List<DateTime>; 

while(currentDate <= endDate) 
{ 
    if(existingDates.contains(currentDate)) 
     missingDates.Add(currentDate); 

    //Increment date 
    currentDate = currentDate.AddDays(1); 
} 

Stosując ten przykład wystarczy załadować „existingDates” z odpowiednimi wartościami, a następnie lista „missingDates” będą miały wyniki

+0

Czy jest to dobre podejście do korzystania .Contains (..) nie? Dopasuj całą tablicę do jednego elementu w samej iteracji. Nie testowałem, ale szukałem tu trafień Where and Count <1. – Independent

1
var dates = new List<DateTime> 
       { 
        new DateTime(2010, 01, 01), 
        new DateTime(2010, 01, 02), 
        new DateTime(2010, 01, 03), 
        new DateTime(2010, 01, 05) 
       }; 

var targetDate = new DateTime(2010, 01, 01); 

var missingDates = new List<DateTime>(); 
while (targetDate <= new DateTime(2010, 01, 06)) 
{ 
    if (!dates.Contains(targetDate)) 
     missingDates.Add(targetDate); 

    targetDate = targetDate.AddDays(1); 
} 

foreach (var date in missingDates) 
    Debug.WriteLine(date.ToString()); 

Jeśli myśleliście rozwiązać ten jest LINQ, Nie wierzę, że jest to możliwe, chyba że masz również listę wszystkich dat między datą minimalną a maksymalną. W SQL jest to tabela kalendarza, która zawiera wszystkie daty w danym okresie.

Oto rozwiązanie LINQ gdzie tworzę listę Kalendarz wspomniałem powyżej, a następnie zapytać o brakujących dat:

var dates = new List<DateTime> 
       { 
        new DateTime(2010, 01, 01), 
        new DateTime(2010, 01, 02), 
        new DateTime(2010, 01, 03), 
        new DateTime(2010, 01, 05) 
       }; 
var calendar = new List<DateTime>(); 
var targetDate = new DateTime(2010, 01, 01); 
while (targetDate <= new DateTime(2010, 01, 06)) 
{ 
    calendar.Add(targetDate); 
    targetDate = targetDate.AddDays(1); 
} 

var missingDates = (from date in calendar 
       where !dates.Contains(date) 
       select date).ToList(); 

foreach (var date in missingDates) 
    Debug.WriteLine(date.ToString()); 
1

Lazy oceniano pomocy metody pomocnika w generowaniu wykaz dat do porównania z. Być może chce profilu wydajności tej metody dla dużych kolekcji.

void Main() 
{ 
    var dates = new[] {new DateTime(2000,1,1), new DateTime(2000,1,5)}; 
    DateHelper.Range(new DateTime(2000,1,1), new DateTime(2000,1,5)).Except(dates).Dump(); 
} 

// Define other methods and classes here 
public static class DateHelper { 
    public static IEnumerable<DateTime> Range(DateTime start, DateTime end) { 
     var days = end.Subtract(start).Days; 
     var next = start; 
     for(var i = 0; i<days; i++) { 
      next = next.AddDays(1); 
      yield return next; 
     } 
    } 
} 
4

W .NET 2.0 :)

static void Main(string[] args) 
    { 
     List<DateTime> dates = new List<DateTime>(); 
     dates.Add(new DateTime(2010, 01, 27)); 
     dates.Add(new DateTime(2010, 01, 30)); 
     dates.Add(new DateTime(2010, 01, 31)); 
     dates.Add(new DateTime(2010, 02, 01)); 


     DateTime startDate = new DateTime(2010, 01, 25); 
     DateTime endDate = new DateTime(2010, 02, 02); 

     List<DateTime> missingDates = new List<DateTime>(GetMissingDates(dates, startDate, endDate)); 

    } 

    private static IEnumerable<DateTime> GetMissingDates(IList<DateTime> dates, DateTime startDate, DateTime endDate) 
    { 
     TimeSpan _timeStamp = endDate - startDate; 
     DateTime _tempDateTime = startDate; 
     IList<DateTime> _dateTimeRange = new List<DateTime>(); 
     IList<DateTime> _missingDates = new List<DateTime>(); 

     for (int i = 0; i <= _timeStamp.Days; i++) 
     { 
      _dateTimeRange.Add(_tempDateTime); 
      _tempDateTime = _tempDateTime.AddDays(1); 
     } 

     foreach (DateTime dt in _dateTimeRange) 
     { 
      if (!dates.Contains(dt)) 
       yield return dt; 
     } 
    } 
+0

+1 Dla implantów 2.0! –

Powiązane problemy