Comment vérifier l’intersection des périodes DateTime

J’ai quatre objects DateTime. A1, A2 et B1, B2.

J’ai besoin de savoir que la période A1-A2 ne recoupe pas la période B1-B2. Mais je ne veux pas écrire de code sale, comme beaucoup de blocs.

if (A1  B1) { return false; } 

…. etc.

ÉDITÉ

J’ai essayé d’utiliser celui-ci: Comparaison des gammes

 DateTime A1 = DateTime.MinValue.AddMinutes(61); DateTime A2 = DateTime.MinValue.AddHours(1.2); DateTime B1 = DateTime.MinValue.AddMinutes(5); DateTime B2 = DateTime.MinValue.AddHours(1); Console.WriteLine(Range.Overlap( new Range(A1, A2), new Range(B1, B2) )); 

C’est retourné vrai mais je m’attendais à faux . Parce que ce code retourne toujours vrai

  if (left.Start.CompareTo(left.Start) == 0) { return true; } 

    Je ne crois pas qu’il y aura une quelconque manière de code “facile” à écrire; vous devez tenir compte de 4 cas d’utilisation distincts. Si vous devez souvent faire ce type de vérification, j’écrirais une méthode d’extension. Sinon, il vous suffit de vérifier ces conditions:

      |--- Date 1 ---| | --- Date 2 --- | | --- Date 1 --- | | --- Date 2 ---- | | -------- Date 1 -------- | | --- Date 2 --- | | --- Date 1 --- | | -------- Date 2 -------- | 

    EDIT: Pour fournir le code actuel:

     public class DateTimeRange { public DateTime Start { get; set; } public DateTime End { get; set; } public bool Intersects(DateTimeRange test) { if(this.Start > this.End || test.Start > test.End) throw new InvalidDateRangeException(); if(this.Start == this.End || test.Start == test.End) return false; // No actual date range if(this.Start == test.Start || this.End == test.End) return true; // If any set is the same time, then by default there must be some overlap. if(this.Start < test.Start) { if(this.End > test.Start && this.End < test.End) return true; // Condition 1 if(this.End > test.End) return true; // Condition 3 } else { if(test.End > this.Start && test.End < this.End) return true; // Condition 2 if(test.End > this.End) return true; // Condition 4 } return false; } } 

    Cela devrait couvrir les cas d’utilisation.

    Si dans votre programme, les plages A1-A2 et B1-B2 sont “correctes” en ce sens que l’on sait que A1 <= A2 et B1 <= B2

    alors votre test de non-intersection est tout simplement

     if(A1>B2 || B1>A2) 

    Remarque J’ai passé sous silence s’il s’agit de> ou> =. Le choix approprié de l’opérateur dépend de la manière dont vous avez défini vos plages pour inclure ou exclure leurs points d’extrémité. c’est-à-dire s’ils représentent des intervalles fermés, ouverts ou semi-ouverts.

    Time Period Library pour .NET semble intéressant.

    Des méthodes telles que IsSamePeriod, HasInside, OverlapsWith ou IntersectsWith sont disponibles pour faciliter la recherche de variantes spéciales, souvent utilisées, de telles relations de période.

    Mon approche consiste à créer une classe appelée Period contenant les propriétés Start et End (DateTime). Cette classe peut avoir des méthodes ou des méthodes d’extension pour calculer des choses telles que les intersections. Disons que vous avez une méthode comme celle-ci dans votre classe de période:

     public bool IntersectsWith(Period otherPeriod) { return !(this.Start > otherPeriod.End || this.End < otherPeriod.Start); } 

    Ensuite, vous pouvez écrire le code comme ceci:

     if (!periodA.IntersectsWith(periodB)) { return false; } 

    Le code que vous avez essayé avait un bug, je l’ai corrigé:

    Essaye ça:

     class Range where T : IComparable { public T Start { get; private set;} public T End { get; private set;} public Range(T start, T end) { //Always ensure that Start < End if(start.CompareTo(end) >= 0) { var temp = end; end = start; start = temp; } Start = start; End = end; } } static class Range { //Based on Eric's idea of doing negative check to figure out //how many ways there are for ranges to NOT overlap. public static bool EricOverlap(Range left, Range right) where T : IComparable { if (right.Start.CompareTo(left.End) > 0) return false; if (left.Start.CompareTo(right.End) > 0) return false; return true; } public static bool Overlap(Range left, Range right) where T : IComparable { if (left.Start.CompareTo(right.Start) == 0) { return true; } else if (left.Start.CompareTo(right.Start) > 0) { return left.Start.CompareTo(right.End) <= 0; } else { return right.Start.CompareTo(left.End) <= 0; } } } 

    Aucun moyen de le contourner:

    * Édité pour simplification:

    En supposant que B2> B1 et A2> A1:

     if (A2 >= B1 && A1 <= B2) { // some part of a1-a2 is in b1-b2 } 

    Cela détectera si une partie de A1-A2 est dans B1-B2.

    Si vous devez détecter si A1-A2 est complètement dans B1-B2:

     if (B1 <= A1 && B2 >= A2) { // all of a1-a2 is in b1-b2 } 

    Cette classe de test unitaire accompagne la solution ci-dessus de Tejs utilisant la classe DateTimeRange (constructeur modifié). Sa solution est correcte et ces tests le prouvent (au cas où vous voudriez copier en production . :))

     [TestClass] public class DateTimeRangeTests { [TestMethod] public void overlap_dates_is_interscected_second_newer_test() { //|--- Date 1 ---| // | --- Date 2 --- | DateTime baseTime = DateTime.Now; var r1 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2)); var r2 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-1)); Assert.IsTrue(r1.Intersects(r2)); } [TestMethod] public void overlap_dates_is_interscected_second_older_test() { // |--- Date 1 ---| // | --- Date 2 --- | DateTime baseTime = DateTime.Now; var r1 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-1)); var r2 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2)); Assert.IsTrue(r1.Intersects(r2)); } [TestMethod] public void overlap_dates_is_interscected_second_subset_of_first_test() { //| -------- Date 1 -------- | // | --- Date 2 --- | DateTime baseTime = DateTime.Now; var r1 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-1)); var r2 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-2)); Assert.IsTrue(r1.Intersects(r2)); } [TestMethod] public void overlap_dates_is_interscected_second_superset_of_first_test() { //| -------- Date 1 -------- | // | --- Date 2 --- | DateTime baseTime = DateTime.Now; var r1 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-2)); var r2 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-1)); Assert.IsTrue(r1.Intersects(r2)); } [TestMethod] public void non_intersects_dates_when_second_before_first_test() { // | --- Date 1 -------- | // | --- Date 2 --- | DateTime baseTime = DateTime.Now; var r1 = new DateTimeRange(baseTime.AddDays(-1), baseTime.AddDays(0)); var r2 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2)); Assert.IsFalse(r1.Intersects(r2)); } [TestMethod] public void non_intersects_dates_when_second_after_first_test() { // | --- Date 1 ------ | // | --- Date 2 --- | DateTime baseTime = DateTime.Now; var r1 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2)); var r2 = new DateTimeRange(baseTime.AddDays(-1), baseTime.AddDays(-0)); Assert.IsFalse(r1.Intersects(r2)); } } 

    Je pense que vous pouvez le faire comme ça! ((Fin2 fin1)):

     DateTime start1 = new DateTime(1); DateTime end1 = new DateTime(2); DateTime start2 = new DateTime(1); DateTime end2 = new DateTime(2); Console.WriteLine(!( (end2 < start1) || (start2 > end1) )); //returns true 

    [OU]

     DateTime start1 = new DateTime(1); DateTime end1 = new DateTime(2); DateTime start2 = new DateTime(3); DateTime end2 = new DateTime(4); Console.WriteLine(!( (end2 < start1) || (start2 > end1) )); // returns false 
     public bool Overlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2) { if (endDate1 >= startDate2 && endDate2 >= startDate1) { return true; } if (startDate1 <= endDate2 && startDate2 <= startDate1) { return true; } return false; } 
     DateTime[] start = new DateTime[] { new DateTime(2000, 1, 1), new DateTime(2004, 1, 1), new DateTime(2004, 1, 1), new DateTime(2008, 1, 1) }; /*date that start from*/ DateTime[] end = new DateTime[] { new DateTime(2002, 1, 1), new DateTime(2006, 1, 1), new DateTime(2006, 1, 1), new DateTime(2010, 1, 1) }; /*date that end */ int timeDifference ; TimeSpan timespan; /*buttonclick */ { /*find total days which note overlap*/ for (int i=0; i= end[i]) { timespan = (end[i] - start[i]) + (end[i + 1] - end[i]); } if (end[i] >= end[i + 1] && start[i] <= start[i + 1]) { timespan = (end[i] - start[i]); } if (end[i] > end[i + 1] && start[i] > start[i + 1] && start[i] <= end[i + 1]) { timespan = (end[i] - start[i]) + (end[i + 1] - end[i]); } if (end[i] <= end[i + 1] && start[i] >= start[i + 1]) { timespan = (end[i + 1] - start[i + 1]); } timeDifference = timespan.Days + timeDifference; } MessageBox.Show(timeDifference.ToSsortingng()); } }} 

    Pourquoi ne pas vérifier si vos périodes ne se chevauchent PAS? Ensuite, si la condition de non-chevauchement est fausse, cela signifie qu’elles se chevauchent:

      bool NotOverlapping = (start1 < start2 && end1 < start2) || (start1 > end2 && end1 > end2); return !NotOverlapping // !NotOverlapping == Overlapping