2010-09-24 228 views
9

我有以下類:檢查的日期範圍的日期範圍內

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恩,我開始迷惑自己,並希望有人做了類似的事情,他們可以分享。由於

回答

14

基本上,日期範圍重疊的另一如果任何其結局是在另一個範圍內,反之亦然。

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); 
+0

感謝大家的回覆,但我更喜歡這一個,因爲它是最容易理解的哈哈。 – nfplee 2010-09-24 17:53:54

1

像這樣的情況應該做的伎倆:

newItem.StartDate <= range.EndDate && newItem.EndDate.HasValue && newItem.EndDate >= range.StartDate 
+0

這是非常符合邏輯和天才的解決方案。 Thnx @Joachim VR – 2017-05-06 08:23:39

5

所以,如果我理解正確的這 - 你要確保日期範圍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)) 
+0

您還應該檢查空值。 – jimplode 2010-09-24 12:12:47

2

下面是使用Collection<T>溶液(缺少null參數驗證和確認中MembershipEndDate > 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); 
    } 
} 
0

如果你不這樣做有不同的排序標準,然後開始按順序維護您的列表。由於之前添加的對象不允許重疊,因此一旦知道添加新對象的位置,您只需比較任一側的單個對象以確保允許新對象。您還需要考慮「早期」對象的結束日期是否與「稍後」對象的開始日期重疊,因爲此排序使得重疊的其他可能性無關。因此,除了簡化檢測重疊的問題,我們可以將複雜度從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。如果拋出異常更合適,這是一個簡單的修改。

0
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; 
     } 
    } 
1

有點晚了,但我在答案/評論的任何地方都找不到這種模式。

if (startDate1 <= endDate2 && startDate2 <= endDate1) 
    { 
    // Overlaps. 
    } 
+0

[這裏是一個例子](https://dotnetfiddle.net/aQuvE3) – crosstalk 2016-07-13 07:52:11