代码之家  ›  专栏  ›  技术社区  ›  nfplee

检查日期范围是否在日期范围内

c#
  •  10
  • nfplee  · 技术社区  · 14 年前

    我有以下课程:

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

    我以为这很简单,但到目前为止,我的尝试都是错误的,我开始迷惑自己,希望有人做了类似的事情,他们可以分享。谢谢

    7 回复  |  直到 11 年前
        1
  •  16
  •   Dan Dumitru    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);
    
        2
  •  7
  •   mbdavis    9 年前

    所以如果我理解正确-你想确定日期范围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))
    
        3
  •  3
  •   Joachim VR    14 年前

    像这样的情况应该可以做到:

    newItem.StartDate <= range.EndDate && newItem.EndDate.HasValue && newItem.EndDate >= range.StartDate
    
        4
  •  2
  •   Ani    14 年前

    这里有一个解决方案(缺少 null 参数验证,以及 Membership EndDate > StartDate )使用 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);
       }
    }
    
        5
  •  2
  •   crosstalk    8 年前

    有点晚了,但我在答案/评论中找不到这种模式。

        if (startDate1 <= endDate2 && startDate2 <= endDate1)
        {
         // Overlaps.
        }
    
        6
  •  0
  •   Jon Hanna    14 年前

    如果你没有不同的排序标准,那么从保持列表的顺序开始。由于之前添加的对象不允许重叠,因此一旦知道要添加新对象的位置,只需比较任意一侧的单个对象即可确保允许添加新对象。您还只需要考虑“较早”对象的结束日期是否与“较晚”对象的开始日期重叠,因为这种顺序使得重叠的另一种可能性无关紧要。

    因此,除了简化检测重叠的问题外,我们还可以将复杂性从O(n)of降低到O(logn),而不是与所有现有项进行比较,而是与通过O(logn)搜索找到的0-2进行比较。

    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 如果无法添加到列表中。如果抛出异常更合适,那么这是一个简单的修改。

        7
  •  0
  •   swade1987    12 年前
    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;
            }
        }
    
        8
  •  0
  •   Thiren Govender    4 年前

    我想出了以下方法来检查日期是否重叠,这可能不是最有效的方法,但我希望这有帮助。。

    public static bool DateRangesOverlap(DateTime startDateA, DateTime endDateA, DateTime startDateB, DateTime endDateB)
    {
        var allDatesA = new List<DateTime>();
        var allDatesB = new List<DateTime>();
    
        for (DateTime date = startDateA; date <= endDateA; date = date.AddDays(1))
        {
            allDatesA.Add(date);
        }
    
        for (DateTime date = startDateB; date <= endDateB; date = date.AddDays(1))
        {
            allDatesB.Add(date);
        }
    
        var isInRange = false;
        foreach (var date in allDatesA)
        {
            var existsInAllDatesB = allDatesB.Any(x => x == date);
            if (existsInAllDatesB)
            {
                isInRange = true;
                break;
            }
        }
    
        return isInRange;
    }