2010-09-24 52 views
9

Tôi có lớp sau:Kiểm tra nếu một phạm vi ngày trong một phạm vi ngày

public class Membership 
{ 
    public DateTime StartDate { get; set; } 
    public DateTime? EndDate { get; set; } // If null then it lasts forever 
} 

tôi cần phải chắc chắn rằng khi thêm vào danh sách sau đó mục mới không chồng chéo các ngày từ mục hiện có :

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

Ví dụ thực hiện:

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

tôi nghĩ đây sẽ là đơn giản nhưng cho đến nay những nỗ lực của tôi đều được wro ng và tôi bắt đầu nhầm lẫn bản thân mình và hy vọng ai đó đã làm điều gì đó tương tự như họ có thể chia sẻ. Cảm ơn

Trả lời

14

Về cơ bản, phạm vi ngày trùng khác nếu bất kỳ kết thúc của nó là trong phạm vi khác hoặc ngược lại.

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)) 
     ); 
} 

Với việc sử dụng:

if (AllowedToAdd(membershipList, newItem)) 
    membershipList.Add(newItem); 
+0

Cảm ơn bạn đã trả lời tất cả mọi người nhưng tôi thích cái này vì nó dễ hiểu nhất lol. – nfplee

1

Một điều kiện như thế này nên làm như lừa:

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

Điều này rất hợp lý và là giải pháp thiên tài. Thnx @Joachim VR –

5

Vì vậy, nếu tôi hiểu điều này một cách chính xác - bạn muốn chắc chắn phạm vi ngày 2 không nằm trong phạm vi ngày 1?

Ví dụ:

startDate1 = 01/01/2011 

endDate1 = 01/02/2011 

startDate2 = 19/01/2011 

endDate2 = 10/02/2011 

này phải là một trường hợp đơn giản của:

if ((startDate2 >= startDate1 && startDate2 <= endDate1) || 
    (endDate2 >= startDate1 && endDate2 <= endDate1)) 
+0

bạn cũng nên kiểm tra giá trị null. – jimplode

2

Dưới đây là một giải pháp (thiếu null luận-xác nhận, và xác nhận trong vòng Membership rằng EndDate > StartDate) sử dụng Collection<T>:

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

Nếu bạn không có các tiêu chí khác nhau để sắp xếp, sau đó bắt đầu bằng cách duy trì danh sách của bạn theo thứ tự. Vì không có đối tượng được thêm trước nào được phép chồng lên nhau, khi bạn biết điểm mà bạn sẽ thêm một đối tượng mới, bạn chỉ cần so sánh các đối tượng đơn ở hai bên để đảm bảo đối tượng mới được cho phép. Bạn cũng chỉ cần cân nhắc xem ngày kết thúc của đối tượng "trước đó" có trùng lặp với ngày bắt đầu của đối tượng "sau này" hay không, vì thứ tự này làm cho khả năng khác của một chồng chéo không liên quan. Do đó cũng như đơn giản hóa câu hỏi phát hiện sự chồng chéo, chúng ta có thể giảm độ phức tạp từ O (n) sang O (log n), thay vì so sánh với tất cả các mục hiện có, chúng ta so sánh với 0-2 chúng ta ' đã tìm thấy thông qua tìm kiếm 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; 
} 

Lợi nhuận trên false nếu không thể thêm vào danh sách. Nếu nó sẽ là thích hợp hơn để ném một ngoại lệ, đây là một sửa đổi dễ dàng.

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

Một chút trễ nhưng tôi không thể tìm thấy mẫu này ở bất kỳ đâu trong câu trả lời/nhận xét.

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

[Và đây là một ví dụ] (https://dotnetfiddle.net/aQuvE3) – crosstalk

Các vấn đề liên quan