una saber rango fechas fecha esta dentro buscar datetime math language-agnostic

datetime - saber - Determine si dos rangos de fechas se superponen



buscar una fecha en un rango de fechas en excel (30)

lo más simple

La forma más sencilla es utilizar una biblioteca dedicada bien diseñada para el trabajo de fecha y hora.

someInterval.overlaps( anotherInterval )

java.time & ThreeTen-Extra

Lo mejor en el negocio es el marco java.time integrado en Java 8 y java.time posteriores. Agregue a eso el proyecto ThreeTen-Extra que complementa java.time con clases adicionales, específicamente la clase de Interval que necesitamos aquí.

En cuanto a la etiqueta de language-agnostic en esta pregunta, el código fuente de ambos proyectos está disponible para su uso en otros idiomas (tenga en cuenta sus licencias).

Interval

La clase Interval es práctica, pero requiere momentos de fecha y hora (objetos java.time.Instant ) en lugar de valores de solo fecha. Así que procedemos utilizando el primer momento del día en UTC para representar la fecha.

Instant start = Instant.parse( "2016-01-01T00:00:00Z" ); Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );

Cree un Interval para representar ese lapso de tiempo.

Interval interval_A = Interval.of( start , stop );

También podemos definir un Interval con un momento de inicio más una Duration .

Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" ); Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );

Comparando con la prueba de superposiciones es fácil.

Boolean overlaps = interval_A.overlaps( interval_B );

Puede comparar un Interval con otro Interval o Instant :

Todos estos utilizan el enfoque semiabierto para definir un lapso de tiempo donde el comienzo es inclusivo y el final es exclusivo .

Dados dos rangos de fechas, ¿cuál es la forma más simple o eficiente de determinar si los dos rangos de fechas se superponen?

Como ejemplo, supongamos que tenemos rangos indicados por las variables DateTime StartDate1 a EndDate1 y StartDate2 a EndDate2 .


Aquí está mi solución en Java , que también funciona en intervalos ilimitados

private Boolean overlap (Timestamp startA, Timestamp endA, Timestamp startB, Timestamp endB) { return (endB == null || startA == null || !startA.after(endB)) && (endA == null || startB == null || !endA.before(startB)); }


Aquí hay otra solución más usando JavaScript. Especialidades de mi solución:

  • Maneja valores nulos como infinito.
  • Supone que el límite inferior es inclusivo y el límite superior exclusivo.
  • Viene con un montón de pruebas

Las pruebas se basan en números enteros, pero como los objetos de fecha en JavaScript son comparables, también puede lanzar dos objetos de fecha. O podrías lanzar en la marca de tiempo de milisegundos.

Código:

/** * Compares to comparable objects to find out whether they overlap. * It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive). * A null value is interpreted as infinity */ function intervalsOverlap(from1, to1, from2, to2) { return (to2 === null || from1 < to2) && (to1 === null || to1 > from2); }

Pruebas:

describe('''', function() { function generateTest(firstRange, secondRange, expected) { it(JSON.stringify(firstRange) + '' and '' + JSON.stringify(secondRange), function() { expect(intervalsOverlap(firstRange[0], firstRange[1], secondRange[0], secondRange[1])).toBe(expected); }); } describe(''no overlap (touching ends)'', function() { generateTest([10,20], [20,30], false); generateTest([20,30], [10,20], false); generateTest([10,20], [20,null], false); generateTest([20,null], [10,20], false); generateTest([null,20], [20,30], false); generateTest([20,30], [null,20], false); }); describe(''do overlap (one end overlaps)'', function() { generateTest([10,20], [19,30], true); generateTest([19,30], [10,20], true); generateTest([10,20], [null,30], true); generateTest([10,20], [19,null], true); generateTest([null,30], [10,20], true); generateTest([19,null], [10,20], true); }); describe(''do overlap (one range included in other range)'', function() { generateTest([10,40], [20,30], true); generateTest([20,30], [10,40], true); generateTest([10,40], [null,null], true); generateTest([null,null], [10,40], true); }); describe(''do overlap (both ranges equal)'', function() { generateTest([10,20], [10,20], true); generateTest([null,20], [null,20], true); generateTest([10,null], [10,null], true); generateTest([null,null], [null,null], true); }); });

Resultado cuando se ejecuta con karma y jazmín y PhantomJS:

PhantomJS 1.9.8 (Linux): Ejecutado 20 de 20 SUCCESS (0.003 secs / 0.004 secs)


Aquí hay un método genérico que puede ser útil localmente.

// Takes a list and returns all records that have overlapping time ranges. public static IEnumerable<T> GetOverlappedTimes<T>(IEnumerable<T> list, Func<T, bool> filter, Func<T,DateTime> start, Func<T, DateTime> end) { // Selects all records that match filter() on left side and returns all records on right side that overlap. var overlap = from t1 in list where filter(t1) from t2 in list where !object.Equals(t1, t2) // Don''t match the same record on right side. let in1 = start(t1) let out1 = end(t1) let in2 = start(t2) let out2 = end(t2) where in1 <= out2 && out1 >= in2 let totover = GetMins(in1, out1, in2, out2) select t2; return overlap; } public static void TestOverlap() { var tl1 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 1:00pm".ToDate(), Out = "1/1/08 4:00pm".ToDate() }; var tl2 = new TempTimeEntry() { ID = 2, Name = "John", In = "1/1/08 5:00pm".ToDate(), Out = "1/1/08 6:00pm".ToDate() }; var tl3 = new TempTimeEntry() { ID = 3, Name = "Lisa", In = "1/1/08 7:00pm".ToDate(), Out = "1/1/08 9:00pm".ToDate() }; var tl4 = new TempTimeEntry() { ID = 4, Name = "Joe", In = "1/1/08 3:00pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() }; var tl5 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 8:01pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() }; var list = new List<TempTimeEntry>() { tl1, tl2, tl3, tl4, tl5 }; var overlap = GetOverlappedTimes(list, (TempTimeEntry t1)=>t1.ID==1, (TempTimeEntry tIn) => tIn.In, (TempTimeEntry tOut) => tOut.Out); Console.WriteLine("/nRecords overlap:"); foreach (var tl in overlap) Console.WriteLine("Name:{0} T1In:{1} T1Out:{2}", tl.Name, tl.In, tl.Out); Console.WriteLine("Done"); /* Output: Records overlap: Name:Joe T1In:1/1/2008 3:00:00 PM T1Out:1/1/2008 8:00:00 PM Name:Lisa T1In:1/1/2008 7:00:00 PM T1Out:1/1/2008 9:00:00 PM Done */ }


Creo que es suficiente decir que los dos rangos se superponen si:

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)


En Microsoft SQL SERVER - Función SQL

CREATE FUNCTION IsOverlapDates ( @startDate1 as datetime, @endDate1 as datetime, @startDate2 as datetime, @endDate2 as datetime ) RETURNS int AS BEGIN DECLARE @Overlap as int SET @Overlap = (SELECT CASE WHEN ( (@startDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and end date outer OR (@endDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and start date outer OR (@startDate2 BETWEEN @startDate1 AND @endDate1) -- only one needed for outer range where dates are inside. ) THEN 1 ELSE 0 END ) RETURN @Overlap END GO --Execution of the above code DECLARE @startDate1 as datetime DECLARE @endDate1 as datetime DECLARE @startDate2 as datetime DECLARE @endDate2 as datetime DECLARE @Overlap as int SET @startDate1 = ''2014-06-01 01:00:00'' SET @endDate1 = ''2014-06-01 02:00:00'' SET @startDate2 = ''2014-06-01 01:00:00'' SET @endDate2 = ''2014-06-01 01:30:00'' SET @Overlap = [dbo].[IsOverlapDates] (@startDate1, @endDate1, @startDate2, @endDate2) SELECT Overlap = @Overlap


En caso de que esté utilizando un intervalo de fechas que aún no haya finalizado (aún en curso), por ejemplo, no se establece endDate = ''0000-00-00'', no puede usar BETWEEN ya que 0000-00-00 no es una fecha válida.

Utilicé esta solución:

(Startdate BETWEEN ''".$startdate2."'' AND ''".$enddate2."'') //overlap: starts between start2/end2 OR (Startdate < ''".$startdate2."'' AND (enddate = ''0000-00-00'' OR enddate >= ''".$startdate2."'') ) //overlap: starts before start2 and enddate not set 0000-00-00 (still on going) or if enddate is set but higher then startdate2

Si startdate2 es más alto que la fecha final, ¡no hay superposición!


En este artículo, la biblioteca de períodos de tiempo para .NET describe la relación de dos períodos de tiempo por la enumeración PeriodRelation :

// ------------------------------------------------------------------------ public enum PeriodRelation { After, StartTouching, StartInside, InsideStartTouching, EnclosingStartTouching, Enclosing, EnclosingEndTouching, ExactMatch, Inside, InsideEndTouching, EndInside, EndTouching, Before, } // enum PeriodRelation


Esta es una extensión de la excelente respuesta de @ charles-bretana.

Sin embargo, la respuesta no hace una distinción entre los intervalos abierto, cerrado y medio abierto (o medio cerrado).

Caso 1 : A, B son intervalos cerrados

A = [StartA, EndA] B = [StartB, EndB] [---- DateRange A ------] (True if StartA > EndB) [--- Date Range B -----] [---- DateRange A -----] (True if EndA < StartB) [--- Date Range B ----]

Superposición iff: (StartA <= EndB) and (EndA >= StartB)

Caso 2 : A, B son intervalos abiertos

A = (StartA, EndA) B = (StartB, EndB) (---- DateRange A ------) (True if StartA >= EndB) (--- Date Range B -----) (---- DateRange A -----) (True if EndA <= StartB) (--- Date Range B ----)

Superposición iff: (StartA < EndB) and (EndA > StartB)

Caso 3 : A, B derecha abierta

A = [StartA, EndA) B = [StartB, EndB) [---- DateRange A ------) (True if StartA >= EndB) [--- Date Range B -----) [---- DateRange A -----) (True if EndA <= StartB) [--- Date Range B ----)

Condición de superposición: (StartA < EndB) and (EndA > StartB)

Caso 4 : A, B dejado abierto

A = (StartA, EndA] B = (StartB, EndB] (---- DateRange A ------] (True if StartA >= EndB) (--- Date Range B -----] (---- DateRange A -----] (True if EndA <= StartB) (--- Date Range B ----]

Condición de superposición: (StartA < EndB) and (EndA > StartB)

Caso 5 : A derecha abierta, B cerrada

A = [StartA, EndA) B = [StartB, EndB] [---- DateRange A ------) (True if StartA > EndB) [--- Date Range B -----] [---- DateRange A -----) (True if EndA <= StartB) [--- Date Range B ----]

Condición de superposición: (StartA <= EndB) and (EndA > StartB)

etc ...

Finalmente, la condición general para que dos intervalos se superpongan es

(StartA <๐Ÿž EndB) y (EndA> ๐Ÿž StartB)

donde ๐Ÿž convierte una desigualdad estricta en una no estricta siempre que la comparación se realice entre dos puntos finales incluidos.


Esta fue mi solución javascript con moment.js:

// Current row dates var dateStart = moment("2014-08-01", "YYYY-MM-DD"); var dateEnd = moment("2014-08-30", "YYYY-MM-DD"); // Check with dates above var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD"); var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD"); // Range covers other ? if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) { return false; } // Range intersects with other start ? if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) { return false; } // Range intersects with other end ? if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) { return false; } // All good return true;


La forma más fácil de hacerlo en mi opinión sería comparar si EndDate1 está antes de StartDate2 y EndDate2 está antes de StartDate1.

Eso, por supuesto, si está considerando intervalos donde StartDate es siempre antes de EndDate.


La solución matemática dada por @Bretana es buena pero descuida dos detalles específicos:

  1. Aspecto de intervalos cerrados o medio abiertos.
  2. intervalos vacíos

Sobre el estado cerrado o abierto de los límites de intervalo, la solución de @Bretana es válida para intervalos cerrados

(StartA <= EndB) y (EndA> = StartB)

Puede reescribirse a intervalos medio abiertos para:

(StartA <EndB) y (EndA> StartB)

Esta corrección es necesaria porque un límite de intervalo abierto no pertenece al rango de valores de un intervalo por definición.

Y sobre intervalos vacíos , bueno, aquí la relación que se muestra arriba NO se cumple. Los intervalos vacíos que no contienen ningún valor válido por definición deben manejarse como un caso especial. Lo demuestro con mi biblioteca de tiempo Java Time4J través de este ejemplo:

MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2)); MomentInterval b = a.collapse(); // make b an empty interval out of a System.out.println(a); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:13,909000000Z) System.out.println(b); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:11,909000000Z)

El corchete inicial "[" indica un inicio cerrado mientras que el último corchete ")" indica un extremo abierto.

System.out.println( "startA < endB: " + a.getStartAsInstant().isBefore(b.getEndAsInstant())); // false System.out.println( "endA > startB: " + a.getEndAsInstant().isAfter(b.getStartAsInstant())); // true System.out.println("a overlaps b: " + a.intersects(b)); // a overlaps b: false

Como se muestra arriba, los intervalos vacíos violan la condición de superposición anterior (especialmente startA <endB), por lo que Time4J (y otras bibliotecas también) deben manejarlo como un caso especial de borde para garantizar que la superposición de cualquier intervalo arbitrario con un intervalo vacío no existe. Por supuesto, los intervalos de fecha (que se cierran por defecto en Time4J pero también pueden estar medio abiertos, como los intervalos de fecha vacíos) se manejan de manera similar.


La solución publicada aquí no funcionó para todos los rangos superpuestos ...

----------------------|-------A-------|---------------------- |----B1----| |----B2----| |----B3----| |----------B4----------| |----------------B5----------------| |----B6----| ----------------------|-------A-------|---------------------- |------B7-------| |----------B8-----------| |----B9----| |----B10-----| |--------B11--------| |----B12----| |----B13----| ----------------------|-------A-------|----------------------

Mi solución de trabajo fue:

AND ( (''start_date'' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and end date outer OR (''end_date'' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and start date outer OR (STARTDATE BETWEEN ''start_date'' AND ''end_date'') -- only one needed for outer range where dates are inside. )


Para razonar sobre las relaciones temporales (o cualquier otra relación de intervalo, venga a eso), considere el Álgebra de intervalos de Allen . Describe las 13 relaciones posibles que pueden tener dos intervalos entre sí. Puede encontrar otras referencias: "Intervalo Allen" parece ser un término de búsqueda operativo. También puede encontrar información sobre estas operaciones en Desarrollo de aplicaciones orientadas en el tiempo de Snodgrass en SQL (PDF disponible en línea en la URL), y en Fecha, Datos temporales de Darwen y Lorentzos y el Modelo relacional (2002) o Teoría temporal y relacional: bases de datos temporales en el modelo relacional y SQL (2014; efectivamente, la segunda edición de TD&RM).

La respuesta corta (ish) es: dados dos intervalos de fecha A y B con componentes .start y .end y la restricción .start <= .end , luego se superponen dos intervalos si:

A.end >= B.start AND A.start <= B.end

Puede ajustar el uso de >= vs > y <= vs < para satisfacer sus requisitos de grado de superposición.

ErikE comenta:

Solo puedes obtener 13 si cuentas las cosas divertidas ... Puedo obtener "15 relaciones posibles que pueden tener dos intervalos" cuando me vuelvo loco con eso. Al contar sensatamente, solo obtengo seis, y si no le importa si A o B son lo primero, solo obtengo tres (sin intersección, intersección parcial, una totalmente dentro de otra). 15 es así: [antes: antes, comienzo, dentro, final, después], [inicio: inicio, dentro, final, después], [dentro: dentro, final, después], [fin: final, después], [ después: después].

Creo que no puedes contar las dos entradas ''antes: antes'' y ''después: después''. Podría ver 7 entradas si compara algunas relaciones con sus inversos (consulte el diagrama en la URL de Wikipedia a la que se hace referencia; tiene 7 entradas, 6 de las cuales tienen una inversa diferente, y las iguales no tienen una inversa distinta). Y si tres es sensible depende de sus necesidades.

----------------------|-------A-------|---------------------- |----B1----| |----B2----| |----B3----| |----------B4----------| |----------------B5----------------| |----B6----| ----------------------|-------A-------|---------------------- |------B7-------| |----------B8-----------| |----B9----| |----B10-----| |--------B11--------| |----B12----| |----B13----| ----------------------|-------A-------|----------------------


Puedes probar esto:

//custom date for example $d1 = new DateTime("2012-07-08"); $d2 = new DateTime("2012-07-11"); $d3 = new DateTime("2012-07-08"); $d4 = new DateTime("2012-07-15"); //create a date period object $interval = new DateInterval(''P1D''); $daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2)); $daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4)); array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);



Si la superposición en sí también debe calcularse, puede utilizar la siguiente fórmula:

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2)) if (overlap > 0) { ... }


Todas las soluciones que verifican una multitud de condiciones en función de dónde se encuentran los rangos entre sí se pueden simplificar en gran medida simplemente asegurando que un rango específico comience antes. Usted se asegura de que el primer rango comience antes (o al mismo tiempo) intercambiando los rangos si es necesario por adelantado.

Luego, puede detectar la superposición si el inicio del otro rango es menor o igual que el primer final del rango (si los rangos son inclusivos, que contienen tanto el inicio como el final) o menor que (si los rangos incluyen el inicio y el final) .

Suponiendo que sea inclusivo en ambos extremos, solo hay cuatro posibilidades, de las cuales una no se solapa:

|----------------------| range 1 |---> range 2 overlap |---> range 2 overlap |---> range 2 overlap |---> range 2 no overlap

El punto final del rango 2 no entra en él. Entonces, en pseudo-código:

def doesOverlap (r1, r2): if r1.s > r2.s: swap r1, r2 if r2.s > r1.e: return false return true

Esto podría simplificarse aún más en:

def doesOverlap (r1, r2): if r1.s > r2.s: swap r1, r2 return r2.s <= r1.e

Si los rangos son inclusivos al inicio y exclusivos al final, solo tiene que reemplazar > con >= en la segunda instrucción if (para el primer segmento de código: en el segundo segmento de código, usará < lugar de <= ):

|----------------------| range 1 |---> range 2 overlap |---> range 2 overlap |---> range 2 no overlap |---> range 2 no overlap

Limita enormemente la cantidad de comprobaciones que debe realizar porque elimina la mitad del espacio del problema antes de tiempo, asegurando que el rango 1 nunca comience después del rango 2.


Tuve una situación en la que teníamos fechas en lugar de fechas, y las fechas solo podían superponerse en el inicio / final. Ejemplo a continuación:

(Verde es el intervalo actual, los bloques azules son intervalos válidos, los rojos son intervalos superpuestos).

Adapté la respuesta de Ian Nelson a la siguiente solución:

(startB <= startA && endB > startA) || (startB >= startA && startB < endA)

Esto coincide con todos los casos de superposición, pero ignora los superpuestos permitidos.


Usando Java util.Date, aquí lo que hice.

public static boolean checkTimeOverlaps(Date startDate1, Date endDate1, Date startDate2, Date endDate2) { if (startDate1 == null || endDate1 == null || startDate2 == null || endDate2 == null) return false; if ((startDate1.getTime() <= endDate2.getTime()) && (startDate2.getTime() <= endDate1.getTime())) return true; return false; }


yo lo haría

StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)

Donde IsBetween es algo como

public static bool IsBetween(this DateTime value, DateTime left, DateTime right) { return (value > left && value < right) || (value < left && value > right); }


Aquí está el código que hace la magia:

var isOverlapping = ((A == null || D == null || A <= D) && (C == null || B == null || C <= B) && (A == null || B == null || A <= B) && (C == null || D == null || C <= D));

Dónde..

  • A -> 1Start
  • B -> 1End
  • C -> 2Comience
  • D -> 2End

¿Prueba? Echa un vistazo a este código de consola de prueba.


(StartA <= EndB) y (EndA> = StartB)

Prueba:
Deje que ConditionA signifique que DateRange A completamente después de DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(Verdadero si StartA > EndB )

Deje que ConditionB signifique que DateRange A es completamente anterior a DateRange B
|---- DateRange A -----| _ _ |---Date Range B ----|
(Verdadero si EndA < StartB )

Entonces existe la superposición si Ni A ni B son ciertas.
(Si un rango no es completamente después del otro,
ni completamente antes que el otro, entonces deben superponerse.)

Ahora una de las leyes de De Morgan dice que:

Not (A Or B) <=> Not A And Not B

Lo que se traduce en: (StartA <= EndB) and (EndA >= StartB)

NOTA: Esto incluye condiciones donde los bordes se superponen exactamente. Si desea excluir eso,
cambia los operadores >= a > , y <= a <

NOTA 2. Gracias a @Baodad, vea este blog , la superposición real es la menor de:
{ endA-startA , endA - startB , endB-startA , endB - startB }

(StartA <= EndB) and (EndA >= StartB) (StartA <= EndB) and (StartB <= EndA)

NOTA 3. Gracias a @tomosius, una versión más corta dice:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Esto es realmente un acceso directo sintáctico para lo que es una implementación más larga, que incluye controles adicionales para verificar que las fechas de inicio estén en o antes de las fechas finales. Derivando esto desde arriba:

Si las fechas de inicio y finalización pueden estar fuera de orden, es decir, si es posible que startA > endA o startB > endB , entonces también debe verificar que estén en orden, lo que significa que debe agregar dos reglas de validez adicionales:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB) o:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB) o,
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB)) o:
(Max(StartA, StartB) <= Min(EndA, EndB)

Pero para implementar Min() y Max() , tienes que codificar (usando C ternary para terseness) ,:
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)


Divide el problema en casos y luego maneja cada caso .

La situación ''dos โ€‹โ€‹intervalos de fechas se intersecan'' está cubierta por dos casos: el primer intervalo de fechas comienza dentro del segundo, o el segundo intervalo de fechas comienza dentro del primero.


Esta fue mi solución, se vuelve verdadera cuando los valores no se superponen:

X START 1 Y END 1

A START 2 B END 2

TEST1: (X <= A || X >= B) && TEST2: (Y >= B || Y <= A) && TEST3: (X >= B || Y <= A) X-------------Y A-----B TEST1: TRUE TEST2: TRUE TEST3: FALSE RESULT: FALSE --------------------------------------- X---Y A---B TEST1: TRUE TEST2: TRUE TEST3: TRUE RESULT: TRUE --------------------------------------- X---Y A---B TEST1: TRUE TEST2: TRUE TEST3: TRUE RESULT: TRUE --------------------------------------- X----Y A---------------B TEST1: FALSE TEST2: FALSE TEST3: FALSE RESULT: FALSE


La respuesta es demasiado simple para mí, así que he creado una declaración de SQL dinámico más genérica que verifica si una persona tiene fechas superpuestas.

SELECT DISTINCT T1.EmpID FROM Table1 T1 INNER JOIN Table2 T2 ON T1.EmpID = T2.EmpID AND T1.JobID <> T2.JobID AND ( (T1.DateFrom >= T2.DateFrom AND T1.dateFrom <= T2.DateTo) OR (T1.DateTo >= T2.DateFrom AND T1.DateTo <= T2.DateTo) OR (T1.DateFrom < T2.DateFrom AND T1.DateTo IS NULL) ) AND NOT (T1.DateFrom = T2.DateFrom)


La siguiente consulta me da los identificadores para los cuales el intervalo de fechas suministrado (fechas de inicio y finalización se superponen con cualquiera de las fechas (fechas de inicio y finalización) en mi nombre de tabla

select id from table_name where (START_DT_TM >= ''END_DATE_TIME'' OR (END_DT_TM BETWEEN ''START_DATE_TIME'' AND ''END_DATE_TIME''))


Para rubí también encontré esto:

class Interval < ActiveRecord::Base validates_presence_of :start_date, :end_date # Check if a given interval overlaps this interval def overlaps?(other) (start_date - other.end_date) * (other.start_date - end_date) >= 0 end # Return a scope for all interval overlapping the given interval, including the given interval itself named_scope :overlapping, lambda { |interval| { :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date] }} end

Lo encontré aquí con una buena explicación -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails


if (StartDate1 > StartDate2) swap(StartDate, EndDate); (StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);


public static class NumberExtensionMethods { public static Boolean IsBetween(this Int64 value, Int64 Min, Int64 Max) { if (value >= Min && value <= Max) return true; else return false; } public static Boolean IsBetween(this DateTime value, DateTime Min, DateTime Max) { Int64 numricValue = value.Ticks; Int64 numericStartDate = Min.Ticks; Int64 numericEndDate = Max.Ticks; if (numricValue.IsBetween(numericStartDate, numericEndDate) ) { return true; } return false; } } public static Boolean IsOverlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2) { Int64 numericStartDate1 = startDate1.Ticks; Int64 numericEndDate1 = endDate1.Ticks; Int64 numericStartDate2 = startDate2.Ticks; Int64 numericEndDate2 = endDate2.Ticks; if (numericStartDate2.IsBetween(numericStartDate1, numericEndDate1) || numericEndDate2.IsBetween(numericStartDate1, numericEndDate1) || numericStartDate1.IsBetween(numericStartDate2, numericEndDate2) || numericEndDate1.IsBetween(numericStartDate2, numericEndDate2)) { return true; } return false; } if (IsOverlap(startdate1, enddate1, startdate2, enddate2)) { Console.WriteLine("IsOverlap"); }