Как проверить, если NSDate происходит между двумя другими NSDates


Я пытаюсь выяснить, попадает ли текущая дата в диапазон дат с помощью NSDate.

например, вы можете получить текущую дату/время с помощью NSDate:

NSDate rightNow = [NSDate date];

затем я хотел бы использовать эту дату, чтобы проверить, если он находится в диапазоне 9 УТРА - 5 ВЕЧЕРА.

10 87

10 ответов:

Я придумал решение. Если у вас есть лучшее решение, не стесняйтесь оставить его, и я отмечу его как правильное.

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

для первой части используйте ответ от @kperryua чтобы построить объекты NSDate, с которыми вы хотите сравнить. Из вашего ответа на ваш собственный вопрос, похоже, что вы это выяснили.

для фактического сравнения дат, я полностью согласен с @Timпрокомментируйте свой ответ. Это более лаконично, но на самом деле точно эквивалентно вашему коду, и я объясню, почему.

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

хотя может показаться, что возвращение оператор должен оценивать оба операнда оператора&&, на самом деле это не так. Ключ - это"оценка короткого замыкания", который реализован на самых разных языках программирования и, конечно же, в C. В основном, операторы & и && "короткое замыкание", если первый аргумент равен 0 (или нет, ноль и т. д.), в то время как | и || сделать то же самое, если первый аргумент не 0. Если date перед beginDate возвращает тест NO даже не нужно сравнивать с endDate. В принципе, он делает то же самое, что и ваш код, но в одном операторе на одной строке, а не 5 (или 7, с пробелами).

это предназначено в качестве конструктивного ввода, так как когда программисты понимают, как их конкретный язык программирования оценивает логические выражения, они могут построить их более эффективно, не так много об эффективности. Однако существуют аналогичные тесты, которые б быть менее эффективным, так как не все операторы короткого замыкания. (Действительно, большинство не может короткое замыкание, например, операторы численного сравнения.) Когда вы сомневаетесь, всегда безопасно быть явным в разрыве вашей логики, но код может быть гораздо более читаемым, когда вы позволяете языку/компилятору обрабатывать мелочи для вас.

версия Brock Woolf в Swift:

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

Если вы хотите узнать, попадает ли текущая дата между двумя заданными моментами времени (9 утра - 5 вечера 7/1/09), используйте NSCalendar и NSDateComponents для создания экземпляров NSDate для желаемого времени и сравните их с текущей датой.

Если вы хотите знать, если текущая дата попадает между этих двух часов день, то вы, вероятно, могли бы пойти в другую сторону. Создайте объект NSDateComponents с помощью и NSCalendar и вашего NSDate и сравните час комплектующие.

Это можно легко сделать, используя временные интервалы дат, например:

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

продолжая решения Куинна и Брокса, очень приятно подкласс реализации 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, конечно, NSDates :)

если вы можете настроить 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

есть лучшее и более быстрое решение этой проблемы.

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 и выше.

лучшая версия в 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
    }
}

С Swift 4.2 и iOS 12, вы можете использовать одно из двух решений ниже, чтобы проверить, если дата происходит между двумя другими датами.


#1. Используя DateInterval ' s contains(_:) метод

DateInterval имеет метод под названием contains(_:). contains(_:) есть следующее объявление:

func contains(_ date: Date) -> Bool

указывает, содержит ли этот интервал заданную дату.

следующий код игровой площадки показывает, как использовать 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. Используя ClosedRange ' s contains(_:) метод

ClosedRange имеет метод под названием contains(_:). contains(_:) есть следующее объявление:

func contains(_ element: Bound) -> Bool

возвращает логическое значение, указывающее, содержится ли данный элемент в диапазоне.

следующий код игровой площадки показывает, как использовать 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