Como verificar se um NSDate ocorre entre dois outros NSDates

Eu estou tentando descobrir se a data atual está dentro de um intervalo de datas usando NSDate.

Por exemplo, você pode obter a data / hora atual usando o NSDate:

NSDate rightNow = [NSDate date]; 

Eu gostaria de usar essa data para verificar se está no intervalo das 9h às 17h .

Eu encontrei uma solução. Se você tiver uma solução melhor, sinta-se à vontade para deixá-la e eu a marcarei como correta.

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

Para a primeira parte, use a resposta de @kperryua para construir os objects NSDate que você deseja comparar. Da sua resposta à sua própria pergunta, parece que você descobriu isso.

Para realmente comparar as datas, eu concordo totalmente com o comentário de @Tim em sua resposta. É mais conciso e na verdade exatamente equivalente ao seu código, e eu explicarei o porquê.

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

Embora possa parecer que a instrução de retorno deve avaliar os dois operandos do operador &&, esse não é realmente o caso. A chave é ” avaliação de curto-circuito “, que é implementada em uma ampla variedade de linguagens de programação, e certamente em C. Basicamente, os operadores & e && “curto-circuito” se o primeiro argumento for 0 (ou NÃO, nulo, etc. .), enquanto | e || faça o mesmo se o primeiro argumento não for 0. Se date for antes de beginDate , o teste retornará NO sem precisar comparar com endDate . Basicamente, ele faz a mesma coisa que seu código, mas em uma única instrução em uma linha, não em 5 (ou 7, com espaço em branco).

Isso se destina a uma input construtiva, pois, quando os programadores entendem a maneira como sua linguagem de programação específica avalia expressões lógicas, eles podem construí-los de maneira mais eficiente, sem muita eficiência. No entanto, existem testes semelhantes que seriam menos eficientes, uma vez que nem todos os operadores estão em curto-circuito. (Na verdade, a maioria não pode causar curto-circuito, como operadores de comparação numérica.) Em caso de dúvida, é sempre seguro ser explícito ao desmembrar sua lógica, mas o código pode ser muito mais legível quando você permite que o idioma / compilador manipule as pequenas coisas para voce.

Versão Brock Woolf no 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 } } 

Se você quiser saber se a data atual está entre dois pontos determinados no tempo (9:00 – 17:00 em 01/07/09), use NSCalendar e NSDateComponents para criar instâncias NSDate para os horários desejados e compare-os com a data atual.

Se você quer saber se a data atual cai entre essas duas horas todos os dias, então você provavelmente poderia ir para o outro lado. Crie um object NSDateComponents com e NSCalendar e seu NSDate e compare os componentes de hora.

Isso pode ser feito facilmente usando os intervalos de datas, assim:

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

Continuando com as soluções de Quinn e Brock, é muito bom subclassificar a implementação do NSDate, então ele pode ser usado em qualquer lugar como este:

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

E em qualquer parte do seu código você pode usá-lo como:

 [myNSDate isBetweenDate:thisNSDate andDate:thatNSDate]; 

(myNSDate, thisNSDate e thatNSDate são, obviamente, NSDates 🙂

Existe uma solução melhor e mais atraente para este problema.

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

Então você pode chamar assim.

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

Mesmo você pode passar a data aleatoriamente, pois esta extensão verifica qual é o mínimo e qual não.

você pode usá-lo no swift 3 e acima.

Se você conseguir segmentar o iOS 10.0 + / macOS 10.12+, use a class DateInterval .

Primeiro, crie um intervalo de datas com uma data de início e de término:

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

Em seguida, verifique se a data está no intervalo usando o método contains de DateInterval :

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

Uma versão melhor no 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 } }