检查的日期范围的日期范围内
我有以下类:检查的日期范围的日期范围内
public class Membership
{
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; } // If null then it lasts forever
}
我需要确保添加到下面的列表,新项目不重叠,从现有项目的日期时, :
var membership = new List<Membership>
{
new Membership { StartDate = DateTime.UtcNow.AddDays(-10), EndDate = DateTime.UtcNow.AddDays(-5) },
new Membership { StartDate = DateTime.UtcNow.AddDays(-5), EndDate = null }
};
例如做:
var newItem = new Membership { StartDate = DateTime.UtcNow.AddDays(-15), EndDate = DateTime.UtcNow.AddDays(-10) }; // Allowed
var newItem2 = new Membership { StartDate = DateTime.UtcNow.AddDays(-15), EndDate = null }; // Not Allowed
if (AllowededToAdd(newItem))
membership.Add(newItem);
if (AllowededToAdd(newItem2))
membership.Add(newItem2);
我想这将是简单的,但到目前为止,我的尝试已经全部WRO恩,我开始迷惑自己,并希望有人做了类似的事情,他们可以分享。由于
基本上,日期范围重叠的另一如果任何其结局是在另一个范围内,反之亦然。
static bool AllowedToAdd(List<Membership> membershipList, Membership newItem)
{
return !membershipList.Any(m =>
(m.StartDate < newItem.StartDate &&
newItem.StartDate < (m.EndDate ?? DateTime.MaxValue))
||
(m.StartDate < (newItem.EndDate ?? DateTime.MaxValue) &&
(newItem.EndDate ?? DateTime.MaxValue) <= (m.EndDate ?? DateTime.MaxValue))
||
(newItem.StartDate < m.StartDate &&
m.StartDate < (newItem.EndDate ?? DateTime.MaxValue))
||
(newItem.StartDate < (m.EndDate ?? DateTime.MaxValue) &&
(m.EndDate ?? DateTime.MaxValue) <= (newItem.EndDate ?? DateTime.MaxValue))
);
}
用法用量:
if (AllowedToAdd(membershipList, newItem))
membershipList.Add(newItem);
像这样的情况应该做的伎俩:
newItem.StartDate <= range.EndDate && newItem.EndDate.HasValue && newItem.EndDate >= range.StartDate
这是非常符合逻辑和天才的解决方案。 Thnx @Joachim VR – 2017-05-06 08:23:39
所以,如果我理解正确的这 - 你要确保日期范围2不是日期范围内,1?
例如:
startDate1 = 01/01/2011
endDate1 = 01/02/2011
和
startDate2 = 19/01/2011
endDate2 = 10/02/2011
这应该是简单的情况下的:
if ((startDate2 >= startDate1 && startDate2 <= endDate1) ||
(endDate2 >= startDate1 && endDate2 <= endDate1))
您还应该检查空值。 – jimplode 2010-09-24 12:12:47
下面是使用Collection<T>
溶液(缺少null
参数验证和确认中Membership
是EndDate > StartDate
):
public class Membership
{
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; } // If null then it lasts forever
private DateTime NullSafeEndDate { get { return EndDate ?? DateTime.MaxValue; } }
private bool IsFullyAfter(Membership other)
{
return StartDate > other.NullSafeEndDate;
}
public bool Overlaps(Membership other)
{
return !IsFullyAfter(other) && !other.IsFullyAfter(this);
}
}
public class MembershipCollection : Collection<Membership>
{
protected override void InsertItem(int index, Membership member)
{
if(CanAdd(member))
base.InsertItem(index, member);
else throw new ArgumentException("Ranges cannot overlap.");
}
public bool CanAdd(Membership member)
{
return !this.Any(member.Overlaps);
}
}
如果你不这样做有不同的排序标准,然后开始按顺序维护您的列表。由于之前添加的对象不允许重叠,因此一旦知道添加新对象的位置,您只需比较任一侧的单个对象以确保允许新对象。您还需要考虑“早期”对象的结束日期是否与“稍后”对象的开始日期重叠,因为此排序使得重叠的其他可能性无关。因此,除了简化检测重叠的问题,我们可以将复杂度从O(n)降低到O(log n),而不是与所有现有项目进行比较,我们将其与0-2比较,通过O(log n)搜索找到。
private class MembershipComparer : IComparer<Membership>
{
public int Compare(Membership x, Membership y)
{
return x.StartDate.CompareTo(y.StartDate);
}
}
private static bool AddMembership(List<Membership> lst, Membership ms)
{
int bsr = lst.BinarySearch(ms, new MembershipComparer());
if(bsr >= 0) //existing object has precisely the same StartDate and hence overlaps
//(you may or may not want to consider the case of a zero-second date range)
return false;
int idx = ~bsr; //index to insert at if doesn't match already.
if(idx != 0)
{
Membership prev = lst[idx - 1];
// if inclusive ranges is allowed (previous end precisely the same
// as next start, change this line to:
// if(!prev.EndDate.HasValue || prev.EndDate > ms.StartDate)
if(prev.EndDate ?? DateTime.MaxValue >= ms.StartDate)
return false;
}
if(idx != lst.Count)
{
Membership next = lst[idx];
// if inclusive range is allowed, change to:
// if(!ms.EndDate.HasValue || ms.EndDate > next.StartDate)
if(ms.EndDate ?? DateTime.MaxValue >= next.StartDate)
return false;
}
lst.Insert(idx, ms);
return true;
}
如果无法添加到列表中,则返回false
。如果抛出异常更合适,这是一个简单的修改。
public bool DoesAnOfferAlreadyExistWithinTheTimeframeProvided(int RetailerId, DateTime ValidFrom, DateTime ValidTo)
{
bool result = true;
try
{
// Obtain the current list of coupons associated to the retailer.
List<RetailerCoupon> retailerCoupons = PayPalInStore.Data.RetailerCoupon.Find(x => x.RetailerId == RetailerId).ToList();
// Loop through each coupon and see if the timeframe provided in the NEW coupon doesnt fall between any EZISTING coupon.
if (retailerCoupons != null)
{
foreach (RetailerCoupon coupon in retailerCoupons)
{
DateTime retailerCouponValidFrom = coupon.DateValidFrom;
DateTime retailerCouponValidTo = coupon.DateExpires;
if ((ValidFrom <= retailerCouponValidFrom && ValidTo <= retailerCouponValidFrom) || (ValidFrom >= retailerCouponValidTo && ValidTo >= retailerCouponValidTo))
{
return false;
}
}
}
return result;
}
catch (Exception ex)
{
this.errorManager.LogError("DoesAnOfferAlreadyExistWithinTheTimeframeProvided failed", ex);
return result;
}
}
有点晚了,但我在答案/评论的任何地方都找不到这种模式。
if (startDate1 <= endDate2 && startDate2 <= endDate1)
{
// Overlaps.
}
[这里是一个例子](https://dotnetfiddle.net/aQuvE3) – crosstalk 2016-07-13 07:52:11
感谢大家的回复,但我更喜欢这一个,因为它是最容易理解的哈哈。 – nfplee 2010-09-24 17:53:54