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

StackOverflow https://stackoverflow.com/questions/1072848

Вопрос

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

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

NSDate rightNow = [NSDate date];

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

Это было полезно?

Решение

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

+ (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, с которыми вы хотите сравнить.Судя по вашему ответу на ваш собственный вопрос, похоже, вы это поняли.

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

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

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

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

Версия Брока Вульфа в 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:00 — 17:00 01.07.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 5 вы можете использовать одно из двух решений ниже, чтобы проверить, находится ли дата между двумя другими датами.


№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

Лучшая версия в 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
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top