2010-09-24 4 views
9

J'ai la classe suivante:Vérifiez si une plage de date est comprise dans une plage de dates

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

je dois vous assurer que lors de l'ajout à la liste suivante que le nouvel élément ne se chevauchent pas les dates de l'article existant :

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

Par exemple faire:

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

Je pensais que ce serait simple, mais jusqu'à présent mes tentatives ont tous été WRO ng et je commence à me confondre et espérais que quelqu'un avait fait quelque chose de similaire qu'ils pourraient partager. Merci

Répondre

14

Fondamentalement, une plage de dates chevauche un autre si l'un de ses terminaisons sont dans l'autre gamme, ou vice versa.

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

Avec l'utilisation:

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

Merci pour les réponses tout le monde mais je préfère celui-ci car c'est le plus facile à comprendre lol. – nfplee

1

Une condition comme celui-ci devrait faire l'affaire:

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

Ceci est très logique et une solution de génie. Thnx @Joachim VR –

5

Donc, si je comprends bien - vous voulez faire plage de dates que 2 ne relève pas de plage de dates 1?

Par exemple:

startDate1 = 01/01/2011 

endDate1 = 01/02/2011 

et

startDate2 = 19/01/2011 

endDate2 = 10/02/2011 

Cela devrait être un cas simple:

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

vous devriez également vérifier la valeur nulle. – jimplode

2

est ici une solution (manque null validation des arguments et la validation au sein Membership que EndDate > StartDate) en utilisant 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

Si vous n'êtes pas avoir des critères différents pour le tri, puis commencez par maintenir votre liste dans l'ordre. Comme aucun objet précédemment ajouté ne peut se chevaucher, une fois que vous connaissez le point où vous souhaitez ajouter un nouvel objet, vous n'avez qu'à comparer les objets individuels de chaque côté pour vous assurer que le nouvel objet est autorisé. Il vous suffit également de déterminer si la date de fin de l'objet "antérieur" chevauche la date de début de l'objet "postérieur", car cet ordre rend l'autre possibilité de chevauchement non pertinente. Donc, en plus de simplifier la question de la détection des chevauchements, nous pouvons réduire la complexité de O (n) à O (log n), plutôt que de comparer avec tous les éléments existants, nous comparons avec 0-2 nous ' Nous avons trouvé une recherche 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; 
} 

Les rendements ci-dessus false si elle n'a pas pu ajouter à la liste. S'il serait plus approprié de lancer une exception, c'est une modification facile.

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

Un peu en retard mais je n'ai trouvé ce motif nulle part dans les réponses/commentaires.

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

[Et voici un exemple] (https://dotnetfiddle.net/aQuvE3) – crosstalk

Questions connexes