Diğer iki NSDate arasında bir NSDate olup olmadığını kontrol etme


92

NSDate kullanarak geçerli tarihin bir tarih aralığı içinde olup olmadığını anlamaya çalışıyorum.

Örneğin, NSDate kullanarak geçerli tarih / saati alabilirsiniz:

NSDate rightNow = [NSDate date];

Daha sonra, 09:00 - 17:00 aralığında olup olmadığını kontrol etmek için bu tarihi kullanmak istiyorum .


1
17:00 - 21:00 gibi belirli bir zaman aralığı için NSDate nesnelerinin nasıl oluşturulduğu hakkında daha fazla bilgi için bu sorunun yanıtlarına göz atabilirsiniz.
Marc Charbonneau

Yanıtlar:


170

Bir çözüm buldum. Daha iyi bir çözümünüz varsa, serbest bırakın ve doğru olarak işaretleyeceğim.

+ (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
Bu iyi görünüyor, ancak karışıklığı önlemek için şuna benzer şekilde yeniden adlandırmak isteyebilirsiniz: + (BOOL) date: (NSDate *) date isBetweenDate: (NSDate *) beginDate andDate: (NSDate *) endDate.
Jeff Kelley

3
Kod golfü! Derleyici karşılaştırmada kısa devre yapmalı ve verimliliği kabaca sahip olduğunuza eşit hale getirmelidir: return (([tarih karşılaştırma: başlangıçDate]! = NSOrderedDescending) && ([tarih karşılaştırma: endDate]! = NSOrderedAscending));
Tim

1
Daha da iyisi, bunu bir sınıf yöntemi değil, bir örnek yöntem (NSDate'e ek) yapardım. Şununla giderdim: -isBetweenDate: andDate:
Dave Batton

4
Mükemmel! Bundan bir Kategori yaptım:- (BOOL)isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate;
Matteo Alessani

2
güzel bir çözüm, kısa devre yaparak (ve basit bir De Morgan uygulamasıyla.return !([date compare:startDate] == NSOrderedAscending || [date compare:endDate] == NSOrderedDescending);
Gabriele Petronella

13

İlk kısım için, karşılaştırmak istediğiniz NSDate nesnelerini oluşturmak için @ kperryua'nın cevabını kullanın . Cevabınızdan kendi sorunuza kadar, bunu anladınız gibi görünüyor.

Tarihleri ​​karşılaştırmak için @Tim'in cevabınız hakkındaki yorumuna tamamen katılıyorum . Daha kısa ama aslında tam olarak kodunuza eşdeğer ve nedenini açıklayacağım.

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

Return ifadesinin && operatörünün her iki işlenenini de değerlendirmesi gerekiyor gibi görünse de, aslında durum bu değildir. Anahtar, çok çeşitli programlama dillerinde ve kesinlikle C'de uygulanan " kısa devre değerlendirmesi " dir. Temelde, operatörler &ve &&ilk bağımsız değişken 0 (veya HAYIR, sıfır, vb.) iken |ve ||ilk argüman ise aynı şeyi değil ise 0. dateönce geldiği beginDate, test dönerse NObile karşılaştırmak gerek kalmadan endDate. Temel olarak, kodunuzla aynı şeyi yapar, ancak tek satırda tek bir ifadede, 5 değil (veya beyaz boşluklu 7) değil.

Bunun yapıcı girdi olması amaçlanmıştır, çünkü programcılar kendi programlama dillerinin mantıksal ifadeleri değerlendirme şeklini anladıklarında, verimlilik hakkında çok fazla şey olmadan onları daha etkili bir şekilde oluşturabilirler. Ancak, tüm operatörler kısa devre yapmadığından, daha az verimli olacak benzer testler vardır . (Gerçekten, çoğu kişi kısa devre yapamaz , örneğin sayısal karşılaştırma operatörleri gibi.) Şüpheye düştüğünüzde, mantığınızı ayırmada açık olmak her zaman güvenlidir, ancak dilin / derleyicinin küçük şeyleri işlemesine izin verdiğinizde kod çok daha okunabilir olabilir. senin için.


1
Anlaşılır. Objective-C'nin kısa devre değerlendirmeleri yapacağı hakkında hiçbir fikrim yoktu. Onun sözüne güveneceğim. Bunu benim için açıkladığın için teşekkürler. Sanırım cevabınız benimkinden daha kısa olduğundan sizi doğru olarak işaretleyeceğim ... ve bir şey öğrendim :)
Brock Woolf

Sözümü dinlemeye gerek yok - sadece merakımı gidermek ve bir şeyin işe yarayıp yaramadığının sınırlarını öğrenmek için "güven ama doğrulayın" ilkesini savunuyorum (teşekkürler, Ronald Reagan!). Çağrıldığında döndürdüklerini kaydeden iki yöntemden bir && yaparak doğrulayabilirsiniz; Birincisi 0 döndürürse, ikincisinin asla çağrılmayacağını fark edeceksiniz.
Quinn Taylor

7

Swift'deki Brock Woolf versiyonu:

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

Geçerli tarihin belirtilen iki nokta arasına denk gelip gelmediğini bilmek istiyorsanız (01.07.09'da 09:00 - 17:00), NSCalendar ve NSDateComponents'ı kullanarak istenen zamanlar için NSDate örnekleri oluşturun ve bunları geçerli tarihle karşılaştırın.

Mevcut tarihin her gün bu iki saat arasında olup olmadığını bilmek istiyorsanız, muhtemelen diğer tarafa gidebilirsiniz. NSDateComponents nesnesi ile NSCalendar ve NSDate'inizi oluşturun ve saat bileşenlerini karşılaştırın.


4

İOS 10.0 + / macOS 10.12+ hedefleyebiliyorsanız DateIntervalsınıfı kullanın .

İlk olarak, başlangıç ​​ve bitiş tarihi olan bir tarih aralığı oluşturun:

let start: Date = Date()
let middle: Date = Date()
let end: Date = Date()

let dateInterval: DateInterval = DateInterval(start: start, end: end)

Ardından, aşağıdaki containsyöntemi kullanarak tarihin aralıkta olup olmadığını kontrol edin DateInterval:

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

3

Bu, tarihlerin zaman aralıkları kullanılarak kolayca gerçekleştirilebilir, örneğin:

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

3

Quinn ve Brock'un çözümlerine devam etmek, NSDate uygulamasını alt sınıflara ayırmak çok güzeldir, bu nedenle bunun gibi her yerde kullanılabilir:

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

Ve kodunuzun herhangi bir bölümünde şu şekilde kullanabilirsiniz:

[myNSDate isBetweenDate:thisNSDate andDate:thatNSDate];

(myNSDate, thisNSDate ve thatNSDate elbette NSDates'tir :)


3

Bu problem için daha iyi ve daha hızlı bir çözüm var.

extention Date {
    func isBetween(from startDate: Date,to endDate: Date) -> Bool {
        let result = (min(startDate, endDate) ... max(startDate, endDate)).contains(self)
        return result
    }
}

O zaman buna böyle diyebilirsin.

todayDate.isBetween(from: startDate, to: endDate)

Bu uzantı hangisinin minimum olduğunu ve hangisinin olmadığını kontrol ettiği için rasgele tarih bile geçirebilirsiniz.

swift 3 ve üzeri sürümlerde kullanabilirsiniz.


2

Swift 5 ile, diğer iki tarih arasında bir tarih olup olmadığını kontrol etmek için aşağıdaki iki çözümden birini kullanabilirsiniz.


# 1. Kullanma DateIntervalbireyin contains(_:)yöntemi

DateIntervaladlı bir yöntemi vardır contains(_:). contains(_:)aşağıdaki beyana sahiptir:

func contains(_ date: Date) -> Bool

Bu aralığın verilen tarihi içerip içermediğini gösterir.

Aşağıdaki Oyun Alanı kodu, contains(_:)diğer iki tarih arasında bir tarih olup olmadığını kontrol etmek için nasıl kullanılacağını gösterir :

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. Kullanma ClosedRangebireyin contains(_:)yöntemi

ClosedRangeadlı bir yöntemi vardır contains(_:). contains(_:)aşağıdaki beyana sahiptir:

func contains(_ element: Bound) -> Bool

Verilen öğenin aralıkta yer alıp almadığını gösteren bir Boolean değeri döndürür.

Aşağıdaki Oyun Alanı kodu, contains(_:)diğer iki tarih arasında bir tarih olup olmadığını kontrol etmek için nasıl kullanılacağını gösterir :

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'in daha iyi bir versiyonu:

@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
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.