J'ai quatre objets 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 && A2 > B1)
{
return false;
}
....etc.
ÉDITÉ
J'ai essayé d'utiliser celui-ci: Comparaison de 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<DateTime>(A1, A2),
new Range<DateTime>(B1, B2)
));
Il a retourné true mais je m'attendais à false . Parce que ce code retourne toujours true
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.
Bibliothèque de périodes pour .NET a l’air 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 ces relations de période.
Mon approche consiste à créer une classe appelée Period
qui contient 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<T> where T : IComparable<T>
{
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<T>(Range<T> left, Range<T> right)
where T : IComparable<T>
{
if (right.Start.CompareTo(left.End) > 0)
return false;
if (left.Start.CompareTo(right.End) > 0)
return false;
return true;
}
public static bool Overlap<T>(Range<T> left, Range<T> right)
where T : IComparable<T>
{
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;
}
}
}
Cette classe de tests unitaires accompagne la solution ci-dessus avec Tejs en 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));
}
}
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 permettra de détecter 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
}
Je pense que vous pouvez le faire comme ça! ((Fin2 <début1) || (début2> 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;
}
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
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.Length-2; i++)
{
if (end[i] < end[i + 1] && start[i] < start[i + 1] && start[i + 1] >= 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.ToString());
}
}}