Как проверить пересечение периодов DateTime
У меня есть четыре объекта DateTime.
A1, A2 и B1, B2.
Мне нужно знать, что период A1-A2 не пересекается с периодом B1-B2. Но я не хочу писать грязный код, как многие, если блоки.
if (A1 < B1 && A2 > B1)
{
return false;
}
....
и др.
отредактированы
Я попытался использовать этот: Сравнение диапазонов
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)
));
Он вернул true, но я ожидал false.
Поскольку этот код всегда возвращает true
if (left.Start.CompareTo(left.Start) == 0)
{
return true;
}
Ответы
Ответ 1
Я не верю, что будет какой-нибудь способ "простого" кода писать; вы должны учитывать 4 различных варианта использования. Если вам нужно много чего сделать, я бы написал метод расширения. В противном случае вам просто нужно проверить эти условия:
|--- Date 1 ---|
| --- Date 2 --- |
| --- Date 1 --- |
| --- Date 2 ---- |
| -------- Date 1 -------- |
| --- Date 2 --- |
| --- Date 1 --- |
| -------- Date 2 -------- |
РЕДАКТИРОВАТЬ: предоставить фактический код:
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;
}
}
Это должно охватывать варианты использования.
Ответ 2
Если в вашей программе диапазоны A1-A2 и B1-B2 являются "правильными" в том смысле, что известно, что A1 <= A2 и B1 <= B2
то ваш тест без пересечения просто
if(A1>B2 || B1>A2)
Примечание. Я прочитал, что это > или > =. Правильный выбор оператора зависит от того, как вы определили диапазоны для включения или исключения своих конечных точек; т.е. представляют ли они замкнутые, открытые или полуоткрытые интервалы.
Ответ 3
Библиотека Time Period для .NET выглядит интересной.
Методы, такие как IsSamePeriod, HasInside, OverlapsWith или IntersectsWith доступны для удобства запросов для специальных, часто используемых вариантов таких отношений периода.
Ответ 4
Мой подход заключается в создании класса с именем Period
, который содержит свойства Start
и End
(DateTime). Этот класс может иметь методы или методы расширения для вычисления таких вещей, как пересечения. Скажем, у вас есть такой метод в вашем классе Period:
public bool IntersectsWith(Period otherPeriod)
{
return !(this.Start > otherPeriod.End || this.End < otherPeriod.Start);
}
Затем вы можете написать код следующим образом:
if (!periodA.IntersectsWith(periodB))
{
return false;
}
Ответ 5
В коде, который вы пробовали, есть ошибка, я исправил его:
Попробуйте следующее:
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 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;
}
}
}
Ответ 6
Ничего не стоит вокруг:
* Отредактировано для упрощения:
Предполагая, что B2 > B1 и A2 > A1:
if (A2 >= B1 && A1 <= B2) {
// some part of a1-a2 is in b1-b2
}
Это обнаружит, что какая-либо часть A1-A2 находится в B1-B2.
Если вам нужно определить, полностью ли A1-A2 находится в B1-B2:
if (B1 <= A1 && B2 >= A2) {
// all of a1-a2 is in b1-b2
}
Ответ 7
Этот класс unit test сопровождает решение выше Tejs, используя класс DateTimeRange
(модифицированный конструктор). Его решение правильное, и эти тесты подтверждают это (если вы хотите скопировать в производство:):)
[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));
}
}
Ответ 8
Я думаю, вы можете сделать это так! ((end2 < start1) || (start2 > end1)):
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
[OR]
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
Ответ 9
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;
}
Ответ 10
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());
}
}}
Ответ 11
Как проверить, не перекрываются ли ваши периоды времени? Тогда, если условие не перекрытия является ложным, это означает, что они перекрывают:
bool NotOverlapping = (start1 < start2 && end1 < start2) || (start1 > end2 && end1 > end2);
return !NotOverlapping // !NotOverlapping == Overlapping