2010-09-24 13 views
9

Ich habe die folgende Klasse:Überprüfen Sie, ob ein Datumsbereich ist in einem bestimmten Zeitraum

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

Ich brauche sicher zu machen, wenn Sie die folgende Liste hinzufügen, die das neue Element nicht überlappt die Daten aus vorhandenen Artikel :

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

Zum Beispiel tun:

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

dachte ich, das meine Versuche WRO alle, aber bisher einfach wäre ng und ich fange an, mich zu verwirren und hoffte, dass jemand etwas Ähnliches getan hat, das sie teilen könnten. Dank

Antwort

14

Grundsätzlich ist ein Datumsbereich überlappt eine andere, wenn einer ihrer Endungen innerhalb des anderen Bereichs oder umgekehrt.

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

Mit der Nutzung:

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

Danke für die Antworten jeder, aber ich bevorzuge diesen, da es am einfachsten zu verstehen ist lol. – nfplee

1

Eine Bedingung wie dies den Trick tun sollten:

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

Dies ist sehr logisch und eine geniale Lösung. Thnx @Joachim VR –

5

Also, wenn ich das richtig verstehen - Sie 1 sicher Datumsbereich 2 nicht innerhalb Datumsbereich machen wollen?

Zum Beispiel:

startDate1 = 01/01/2011 

endDate1 = 01/02/2011 

und

startDate2 = 19/01/2011 

endDate2 = 10/02/2011 

Dies ist ein einfacher Fall sein sollte:

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

sollten Sie auch nach dem Nullwert suchen. – jimplode

2

Hier ist eine Lösung (null Argument-Validierung und Validierung innerhalb Membership dass EndDate > StartDate fehlt) mit 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

Wenn Sie nicht tun Haben Sie verschiedene Kriterien für die Sortierung, dann beginnen Sie mit der Pflege Ihrer Liste in der richtigen Reihenfolge. Da sich kein zuvor hinzugefügtes Objekt überlappen darf, müssen Sie, sobald Sie den Punkt kennen, an dem Sie ein neues Objekt hinzufügen möchten, nur die einzelnen Objekte auf beiden Seiten vergleichen, um sicherzustellen, dass das neue Objekt zulässig ist. Sie müssen auch nur berücksichtigen, ob das Enddatum des "früheren" Objekts mit dem Startdatum des "späteren" Objekts überlappt, da diese Reihenfolge die andere Möglichkeit für eine Überlappung irrelevant macht.

Damit vereinfacht sich nicht nur die Frage der Erkennung von Überlappungen, wir können auch die Komplexität von O (n) auf O (log n) reduzieren, anstatt mit allen vorhandenen Elementen zu vergleichen, vergleichen wir mit 0-2 we ' durch eine O (log n) Suche gefunden.

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

Die oben genannten Erträge false wenn es nicht in der Lage in die Liste hinzuzufügen. Wenn es angemessener wäre, eine Ausnahme auszulösen, ist dies eine einfache Modifikation.

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

Ein bisschen spät, aber ich konnte dieses Muster nirgendwo in den Antworten/Kommentaren finden.

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

[Und hier ist ein Beispiel] (https://dotnetfiddle.net/aQuvE3) – crosstalk

Verwandte Themen