2010-04-20 9 views
9

Básicamente solo quiero comprobar si un período de tiempo se solapa con otro. Fecha de finalización nula significa hasta el infinito. ¿Alguien puede acortar esto para mí, ya que es bastante difícil de leer a veces. Saludos¿Alguien puede simplificar este algoritmo para mí?

public class TimePeriod 
    { 
     public DateTime StartDate { get; set; } 
     public DateTime? EndDate { get; set; } 

     public bool Overlaps(TimePeriod other) 
     { 
      // Means it overlaps 
      if (other.StartDate == this.StartDate 
       || other.EndDate == this.StartDate 
       || other.StartDate == this.EndDate 
       || other.EndDate == this.EndDate) 
       return true; 

      if(this.StartDate > other.StartDate) 
      { 
       // Negative 
       if (this.EndDate.HasValue) 
       { 
        if (this.EndDate.Value < other.StartDate) 
         return true; 
        if (other.EndDate.HasValue && this.EndDate.Value < other.EndDate.Value) 
         return true; 
       } 

       // Negative 
       if (other.EndDate.HasValue) 
       { 
        if (other.EndDate.Value > this.StartDate) 
         return true; 
        if (this.EndDate.HasValue && other.EndDate.Value > this.EndDate.Value) 
         return true; 
       } 
       else 
        return true; 
      } 
      else if(this.StartDate < other.StartDate) 
      { 
       // Negative 
       if (this.EndDate.HasValue) 
       { 
        if (this.EndDate.Value > other.StartDate) 
         return true; 
        if (other.EndDate.HasValue && this.EndDate.Value > other.EndDate.Value) 
         return true; 
       } 
       else 
        return true; 

       // Negative 
       if (other.EndDate.HasValue) 
       { 
        if (other.EndDate.Value < this.StartDate) 
         return true; 
        if (this.EndDate.HasValue && other.EndDate.Value < this.EndDate.Value) 
         return true; 
       } 
      } 

      return false; 
     } 
    } 
+0

Guau, eso es una bestia :) –

+2

Una gran pregunta, pero ¿puedo sugerirle un nombre mejor? ¿Qué tal "manera concisa para saber si dos pares DateTime se superponen?" –

+1

Un caso típico de 'fuerza mental bruta' es un problema al intentar/envolver todas las posibles constelaciones. La gente a menudo trata de resolver problemas de forma inmediata, en lugar de pensar realmente en el problema. La solución luego es mucho más fácil y es más probable que sea una clara idea. –

Respuesta

15
public bool Overlaps(TimePeriod other) 
{ 
    return (other.StartDate >= StartDate && 
       (EndDate == null || other.StartDate <= EndDate.Value)) || 
      (StartDate >= other.StartDate && 
       (other.EndDate == null || StartDate <= other.EndDate.Value)) 
} 
+0

@Adam, compruebe su algoritmo ... La primera comparación debe ser startdate y enddate, no ambas startdates. startdate = 5 jan, enddate = 10jan; other.start = 1 de enero, other.enddate = 1 de febrero devolverá falso –

+1

@Charles: No, no lo hará. StartDate> other.StartDate && StartDate

+0

@ Adam, lo siento, mi error, mi algoritmo es correcto ... –

3

mira esto: DateTimeOverlaps

De manera muy general, si todas las variables son datetimes anulables, a continuación,

return (StartA.HasValue? StartA.Value:DateTime.Minimum) <= 
      (EndB.HasValue? EndB.Value:DateTime.Maximum) && 
      (EndA.HasValue? EndA.Value:DateTime.Maximum) >= 
       (StartB.HasValue? StartB.Value:DateTime.Minimum); 

El concepto, (como se explica en el enlace) es muy simple, y es simplemente y concisamente expresado arriba.

Si el inicio es anterior al final de los otros, y el final es posterior al otro comienzo, tiene superposición. Esto lo dice todo, y todo lo que es necesario, en una oración simple con dos cláusulas, y cualquiera que sea el código que se escriba, se debe mapear concisamente a ese concepto simple sin ofuscarlo. Agregar complejidad extra innecesaria no agrega comprensión, solo agrega longitud.

Falla Caso 1: TopStart DESPUÉS otro extremo - no se aprueba

 |----------| 
|--| 

Falla Caso 2: topend pos de inicio - fallan

|-----------| 
        |------| 

En todos los demás casos, de inicio es anterior otro extremo, y el final es después de otro inicio.

caso A

|----------| 
|-----| 

caso B

| ---------| 
|-------------------| 

caso C

|-----------| 
    |------| 

caso D

|-----------| 
     |-------------| 
+0

No creo que maneje fecha de finalización nula – Joshscorp

+0

@Titan, esto se puede corregir fácilmente con ediciones menores ... –

11

¿Qué tal este:

public bool Overlaps(TimePeriod other) 
{ 
    bool isOtherEarlier = this.StartDate > other.StartDate; 
    TimePeriod earlier = isOtherEarlier ? other : this; 
    TimePeriod later = isOtherEarlier ? this : other; 
    return !earlier.EndDate.HasValue || earlier.EndDate > later.StartDate; 
} 
+0

No es exactamente una línea como la solución de Adams, pero creo que es un poco más legible. Pero eso es quizás solo una cuestión de gusto. –

+0

Esto también es incorrecto ... La primera comparación debe verificar esto. Fecha de inicio contra otro. EFechaFecha –

+2

@Charles: También es incorrecto aquí. –

2

Cada vez que usted está tratando con pura lógica booleana, se puede destilar el algoritmo a una sola declaración. Pero no supongas que solo porque puedes, deberías. A menos que el rendimiento sea vital, siempre opte por código legible sobre código compacto. (No es que compacidad == rendimiento, necesariamente)

Esto es fácil de leer porque está compuesto en su totalidad de una sola y expresiones, y es obvio que todos ellos determinan un no-solapamiento:

public bool Overlaps(TimePeriod other) 
{ 
    if (other.EndDate.HasValue && other.EndDate < StartDate) 
     return false; 

    if (EndDate.HasValue && EndDate < other.StartDate) 
     return false; 

    if (!EndDate.HasValue && other.EndDate < StartDate) 
     return false; 

    if (!other.EndDate.HasValue && EndDate < other.StartDate) 
     return false; 

    return true; 
} 
No

que la otras respuestas son malas (me gusta la de Adam, su formato obviamente está diseñado para ayudar a la legibilidad). Solo digo esto porque está claro que eres un principiante y creo que esta es una lección que no se tiene en cuenta lo suficiente (soy culpable).Alguien (creo que Martin Fowler) dijo una vez algo como: "Cualquier tonto puede escribir código que una computadora entienda, pero un buen programador puede escribir código que un humano entienda".

Cuestiones relacionadas