如何检查NSDate是否在其他两个NSDate之间发生


90

我正在尝试使用NSDate找出当前日期是否在日期范围内。

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

NSDate rightNow = [NSDate date];

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


1
您可以查看此问题的答案,以获取有关如何在特定时间段(例如5 pm-9pm)创建NSDate对象的更多信息。
Marc Charbonneau

Answers:


167

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

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

3
看起来不错,但您可能希望将其重命名为:+(BOOL)date:(NSDate *)date isBetweenDate:(NSDate *)beginDate和Date:(NSDate *)endDate以避免混淆。
杰夫·凯利

3
编码高尔夫!编译器应缩短比较的时间,使效率大致等于您的效率:

1
更好的是,我将其设为实例方法(是NSDate的补充),而不是类方法。我会这样:-isBetweenDate:andDate:
Dave Batton 2010年

4
优秀的!我从中得出一个类别:- (BOOL)isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate;
Matteo Alessani

2
很好的解决方案,你甚至可以通过短路(和基本德摩应用使它更简洁。return !([date compare:startDate] == NSOrderedAscending || [date compare:endDate] == NSOrderedDescending);
加布里埃尔Petronella

13

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

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

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

尽管看起来return语句必须同时评估&&运算符的两个操作数,但实际上并非如此。关键是“ 短路评估 ”,它以多种编程语言(当然也可以用C语言)实现。基本上,运算符&&&“短路”(如果第一个参数为0(或NO,nil等)) ,而|||做相同的,如果第一个参数是不是 0.如果date到来之前beginDate,测试的回报NO,甚至无需与比较endDate。基本上,它执行与代码相同的功能,但是在一行中的单个语句中,而不是5(或7,带空格)。

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


1
可以理解的 我不知道Objective-C会使评估短路。我会相信你的意思。感谢您为我解决问题。我想我会把您标记为正确的,因为您的回答比我自己的回答更简洁...而且我学到了一些东西:)
Brock Woolf

无需信守我的诺言–我提倡“信任,但要验证”的原则(感谢罗纳德·里根!)只是为了满足我的好奇心,并了解何时行之有效的事。您可以通过对两种方法进行&&验证,以记录调用时返回的结果;您会注意到,如果第一个返回0,则永远不会调用第二个。
奎因·泰勒,

7

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

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

如果你想知道,如果当前日期这两个小时降到一天,那么你很可能走另一条路。使用和NSCalendar和您的NSDate创建一个NSDateComponents对象,并比较小时组件。


4

如果您可以定位到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)

然后,使用以下contains方法检查日期是否在间隔中DateInterval

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

3

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

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

3

继续使用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当然是NSDate :)


3

有更好更好的解决方案。

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)

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

您可以在3以上版本中使用它。


2

使用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

-1

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
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.