it-swarm.com.ru

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

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

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

NSDate rightNow = [NSDate date];

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

88
Brock Woolf

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

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

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

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

14
Quinn Taylor

Брок Вульф версия в 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
    }
}
8
ChikabuZ

Если вы хотите узнать, попадает ли текущая дата между двумя указанными точками времени (с 9:00 до 17:00 01.07.09), используйте NSCalendar и NSDateComponents, чтобы построить экземпляры NSDate для желаемого времени и сравнить их с текущей датой.

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

5
kperryua

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

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

Продолжая с решениями 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 :) 

3
MiQUEL

Если вы можете использовать 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
2
Bryan Luby

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

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

2
Rehan Ali

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


# 1. Использование метода DateInterval's 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's 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
0
Imanou Petit

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