2010-08-02 34 views
8

Estoy tratando de encontrar las fechas faltantes entre dos variables DateTime para una colección de DateTimes.Buscar fechas faltantes para un rango determinado

Por ejemplo.

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

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

me daría un List<DateTime> de

2010-01-04 
2010-01-06 

que puede pensar de unos pocos era de implementar esto, pero nada limpia y sencilla

¿Alguna idea?

Respuesta

16

puedo pensar en un montón de maneras de implementar esto, por ejemplo:

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); 

Y se podría poner el rango-cosas en una extensión-Método

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)); 
    } 
} 

entonces sería ser simplemente

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); 

Pero tal vez esto no es una solución de rendimiento-alta :-)

+0

Eso es similar a lo que estaba pensando, excepto el uso de un bucle para construir mi rango. Simplemente no me gustó la idea de crear una lista de días cada vez, ya que tengo que hacerlo mucho en silencio. –

+1

+1 Buen uso de Range. – Thomas

+0

Sí, el uso inteligente del rango;) –

2

Según exactamente lo que busca y los tamaños de los conjuntos de datos. Una forma simple sería cargar las fechas en una colección, luego usar un simple bucle. Agregaré un ejemplo de código aquí en un segundo.

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); 
} 

Utilizando este ejemplo sólo tiene que cargar "existingDates" con los valores adecuados, a continuación, la lista "missingDates" tendrá sus resultados

+0

¿Es un buen método para usar .Contains (..) allí? Haga coincidir la matriz completa con un elemento en una iteración de sí mismo. No hice una evaluación comparativa, pero iría por un lugar donde y cuente hits <1 aquí. – 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()); 

Si estabas pensando en la solución de este es LINQ, No creo que sea posible a menos que también haya una lista de todas las fechas entre la fecha mínima y máxima. En SQL, esto equivale a una tabla de calendario que contiene todas las fechas en un período de tiempo determinado.

Aquí es una solución LINQ, donde se crea la lista Calendario he mencionado anteriormente y entonces se le pregunta por las fechas que faltan:

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 evalúa ayudas método de ayuda en la generación de la lista de fechas para comparar. Es posible que desee un perfil de rendimiento de este método para colecciones grandes.

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

En .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 ¡Para la implementación 2.0! –

Cuestiones relacionadas