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

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

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

NSDate rightNow = [NSDate date];

Я бы хотел использовать эту дату, чтобы проверить, находится ли она в диапазоне 9AM - 5PM.

Ответ 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;
}

Ответ 2

Для первой части используйте ответ от @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, ноль и т.д.), а | и || делают то же самое, если первый аргумент не 0. Если date предшествует beginDate, тест возвращает NO, даже не требуя сравните с endDate. В основном, он делает то же самое, что и ваш код, но в одном выражении в одной строке, а не в 5 (или 7, с пробелом).

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

Ответ 3

Версия 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
    }
}

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

Продолжая решения 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 - это, конечно, NSDates:)

Ответ 7

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

Ответ 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)

Даже вы можете передавать дату случайным образом, так как это расширение проверяет, какая из них минимальна, а какая - нет.

вы можете использовать его в быстрой версии 3 и выше.

Ответ 9

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

Ответ 10

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


# 1. Использование DateInterval contains(_:) метод

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. Использование ClosedRange contains(_:) метод contains(_:)

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