【问题标题】:How to Check if an NSDate occurs between two other NSDates如何检查 NSDate 是否发生在其他两个 NSDate 之间
【发布时间】:2010-11-07 13:18:53
【问题描述】:

我正在尝试确定当前日期是否在使用 NSDate 的日期范围内。

例如,您可以使用 NSDate 获取当前日期/时间:

NSDate rightNow = [NSDate date];

然后我想使用该日期来检查它是否在 9AM - 5PM 的范围内。

【问题讨论】:

  • 您可以查看this question 的答案,了解有关如何在特定时间段(例如下午 5 点到晚上 9 点)创建 NSDate 对象的更多信息。

标签: objective-c cocoa cocoa-touch datetime nsdate


【解决方案1】:

我想出了一个解决方案。如果您有更好的解决方案,请随时留下,我会将其标记为正确。

+ (BOOL)date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate
{
    if ([date compare:beginDate] == NSOrderedAscending)
        return NO;

    if ([date compare:endDate] == NSOrderedDescending) 
        return NO;

    return YES;
}

【讨论】:

  • 看起来不错,但您可能希望将其重命名为:+ (BOOL)date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate以避免混淆。
  • 编码高尔夫!编译器应该缩短比较,使效率大致等于你所拥有的: return (([date compare:beginDate] != NSOrderedDescending) && ([date compare:endDate] != NSOrderedAscending));
  • 更好的是,我会将其设为实例方法(NSDate 的补充),而不是类方法。我会这样做:-isBetweenDate:andDate:
  • 太棒了!我由此创建了一个类别:- (BOOL)isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate;
  • 不错的解决方案,您甚至可以通过短路(以及基本的 De Morgan 应用程序。return !([date compare:startDate] == NSOrderedAscending || [date compare:endDate] == NSOrderedDescending);
【解决方案2】:

对于第一部分,使用来自 @kperryua 的答案来构造您要与之比较的 NSDate 对象。从您对自己问题的回答看来,您似乎已经明白了。

对于实际比较日期,我完全同意 @Tim 对您的回答的评论。它更简洁,但实际上完全等同于您的代码,我将解释原因。

+ (BOOL) date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate {
    return (([date compare:beginDate] != NSOrderedAscending) && ([date compare:endDate] != NSOrderedDescending));
}

虽然看起来 return 语句必须计算 && 运算符的两个操作数,但实际上并非如此。关键是“short-circuit evaluation”,它用多种编程语言实现,当然也用 C 语言实现。基本上,运算符 &&&如果第一个参数为 0(或 NO、nil 等),则为“短路”,而 ||| 如果第一个参数为不是 0. 如果date 出现在beginDate 之前,则测试返回NO,甚至不需要与endDate 进行比较。基本上,它与您的代码做同样的事情,但在一行的单个语句中,而不是 5(或 7,带空格)。

这旨在作为建设性的输入,因为当程序员了解他们的特定编程语言评估逻辑表达式的方式时,他们可以更有效地构造它们而无需过多考虑效率。但是,也有类似的测试效率较低,因为并非所有运算符都会短路。 (事实上​​,大多数不能短路,例如数值比较运算符。)如果有疑问,明确分解逻辑总是安全的,但是当你让语言/编译器为您处理小事。

【讨论】:

  • 可以理解。我不知道 Objective-C 会使评估短路。我会相信你的话。感谢您为我解决这个问题。我想我会把你标记为正确的,因为你的答案比我自己的更简洁......而且我学到了一些东西:)
  • 无需相信我的话——我提倡“信任,但要验证”的原则(感谢罗纳德·里根!)如果只是为了满足我的好奇心并了解某事何时有效和无效的界限不。您可以通过对两种方法执行 && 来验证它,这些方法记录它们在调用时返回的内容;您会注意到,如果第一个返回 0,则永远不会调用第二个。
【解决方案3】:

Swift 中的 Brock Woolf 版本:

extension NSDate
{
    func isBetweenDates(beginDate: NSDate, endDate: NSDate) -> Bool
    {
        if self.compare(beginDate) == .OrderedAscending
        {
            return false
        }

        if self.compare(endDate) == .OrderedDescending
        {
            return false
        }

        return true
    }
}

【讨论】:

    【解决方案4】:

    如果您想知道当前日期是否在两个给定时间点之间(2009 年 7 月 1 日上午 9 点到下午 5 点),请使用 NSCalendar 和 NSDateComponents 为所需时间构建 NSDate 实例,并将它们与当前日期进行比较.

    如果您想知道当前日期是否在每天这两个小时之间,那么您可能会采用另一种方式。使用 NSCalendar 和您的 NSDate 创建一个 NSDateComponents 对象并比较小时组件。

    【讨论】:

      【解决方案5】:

      继续使用 Quinn 和 Brock 的解决方案,对 NSDate 实现进行子类化非常好,因此它可以像这样在任何地方使用:

      -(BOOL) isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate {
          return (([self compare:beginDate] != NSOrderedAscending) && ([self compare:endDate] != NSOrderedDescending));
      }
      

      您可以在代码的任何部分将其用作:

      [myNSDate isBetweenDate:thisNSDate andDate:thatNSDate];
      

      (myNSDate, thisNSDate 和 thatNSDate 当然是 N​​SDates :)

      【讨论】:

        【解决方案6】:

        如果您可以针对 iOS 10.0+/macOS 10.12+,请使用 DateInterval 类。

        首先,创建一个包含开始日期和结束日期的日期间隔:

        let start: Date = Date()
        let middle: Date = Date()
        let end: Date = Date()
        
        let dateInterval: DateInterval = DateInterval(start: start, end: end)
        

        然后,使用DateIntervalcontains方法检查日期是否在区间内:

        let dateIsInInterval: Bool = dateInterval.contains(middle) // true
        

        【讨论】:

          【解决方案7】:

          这可以使用日期的时间间隔轻松完成,如下所示:

          const NSTimeInterval i = [date timeIntervalSinceReferenceDate];
          return ([startDate timeIntervalSinceReferenceDate] <= i &&
                  [endDate timeIntervalSinceReferenceDate] >= i);
          

          【讨论】:

            【解决方案8】:

            对于这个问题有更好更快捷的解决方案。

            extention Date {
                func isBetween(from startDate: Date,to endDate: Date) -> Bool {
                    let result = (min(startDate, endDate) ... max(startDate, endDate)).contains(self)
                    return result
                }
            }
            

            那你就可以这样称呼了。

            todayDate.isBetween(from: startDate, to: endDate)
            

            即使您可以随机传递日期,因为此扩展程序会检查哪个是最小值,哪个不是。

            你可以在swift 3及更高版本中使用它。

            【讨论】:

              【解决方案9】:

              使用 Swift 5,您可以使用以下两种解决方案之一来检查日期是否介于其他两个日期之间。


              #1。使用DateIntervalcontains(_:)方法

              DateInterval 有一个名为contains(_:) 的方法。 contains(_:) 有以下声明:

              func contains(_ date: Date) -> Bool
              

              指示此间隔是否包含给定日期。

              以下 Playground 代码展示了如何使用 contains(_:) 来检查某个日期是否介于其他两个日期之间:

              import Foundation
              
              let calendar = Calendar.current
              let startDate = calendar.date(from: DateComponents(year: 2010, month: 11, day: 22))!
              let endDate = calendar.date(from: DateComponents(year: 2015, month: 5, day: 1))!
              let myDate = calendar.date(from: DateComponents(year: 2012, month: 8, day: 15))!
              
              let dateInterval = DateInterval(start: startDate, end: endDate)
              let result = dateInterval.contains(myDate)
              print(result) // prints: true
              

              #2。使用ClosedRangecontains(_:)方法

              ClosedRange 有一个名为contains(_:) 的方法。 contains(_:) 有以下声明:

              func contains(_ element: Bound) -> Bool
              

              返回一个布尔值,指示给定元素是否包含在范围内。

              以下 Playground 代码显示了如何使用 contains(_:) 来检查某个日期是否介于其他两个日期之间:

              import Foundation
              
              let calendar = Calendar.current
              let startDate = calendar.date(from: DateComponents(year: 2010, month: 11, day: 22))!
              let endDate = calendar.date(from: DateComponents(year: 2015, month: 5, day: 1))!
              let myDate = calendar.date(from: DateComponents(year: 2012, month: 8, day: 15))!
              
              let range = startDate ... endDate
              let result = range.contains(myDate)
              //let result = range ~= myDate // also works
              print(result) // prints: true
              

              【讨论】:

                【解决方案10】:

                更好的 Swift 版本:

                @objc public class DateRange: NSObject {
                    let startDate: Date
                    let endDate: Date
                
                    init(startDate: Date, endDate: Date) {
                        self.startDate = startDate
                        self.endDate = endDate
                    }
                
                    @objc(containsDate:)
                    func contains(_ date: Date) -> Bool {
                        let startDateOrder = date.compare(startDate)
                        let endDateOrder = date.compare(endDate)
                        let validStartDate = startDateOrder == .orderedAscending || startDateOrder == .orderedSame
                        let validEndDate = endDateOrder == .orderedDescending || endDateOrder == .orderedSame
                        return validStartDate && validEndDate
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 2010-12-31
                  • 2016-12-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-07-30
                  • 2016-06-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-11-01
                  相关资源
                  最近更新 更多