Comparação de duas NSDates e ignorando o componente de tempo de
-
13-09-2019 - |
Pergunta
O que é o mais eficiente/recomendado maneira de comparar os dois NSDates?Eu gostaria de ser capaz de ver se ambas as datas são no mesmo dia, independentemente do tempo e começaram a escrever algum código que usa o timeIntervalSinceDate:método dentro da NSDate classe e obtém o número inteiro de este valor dividido pelo número de segundos em um dia.Este parece ser prolixo e eu sinto que eu estou faltando alguma coisa óbvia.
O código que eu estou tentando corrigir é:
if (!([key compare:todaysDate] == NSOrderedDescending))
{
todaysDateSection = [eventSectionsArray count] - 1;
}
onde chave e todaysDate são NSDate objetos e todaysDate é criar usando:
NSDate *todaysDate = [[NSDate alloc] init];
Matéria
Dave
Solução
Você define a hora na data para 00:00:00 antes de fazer a comparação:
unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:flags fromDate:date];
NSDate* dateOnly = [calendar dateFromComponents:components];
// ... necessary cleanup
Então você pode comparar os valores da data. Veja o Visão geral na documentação de referência.
Outras dicas
Estou surpreso que nenhuma outra resposta tenha essa opção para obter a data do "início do dia" para os objetos:
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date1 interval:NULL forDate:date1];
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date2 interval:NULL forDate:date2];
Que define date1
e date2
até o início de seus respectivos dias. Se forem iguais, estão no mesmo dia.
Ou esta opção:
NSUInteger day1 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSDayCalendarUnit inUnit: forDate:date1];
NSUInteger day2 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date2];
Que define day1
e day2
a valores um tanto arbitrários que podem ser comparados. Se forem iguais, estão no mesmo dia.
Há um novo método que foi introduzido no NSCalendar com o iOS 8 que facilita muito.
- (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit NS_AVAILABLE(10_9, 8_0);
Você define a granularidade para as unidades que importam. Isso desconsidera todas as outras unidades e limita a comparação com as selecionadas.
Para iOS8 e posterior, verificar se duas datas ocorrerem no mesmo dia é tão simples quanto:
[[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2]
Ver documentação
Esta é uma abreviação de todas as respostas:
NSInteger interval = [[[NSCalendar currentCalendar] components: NSDayCalendarUnit
fromDate: date1
toDate: date2
options: 0] day];
if(interval<0){
//date1<date2
}else if (interval>0){
//date2<date1
}else{
//date1=date2
}
Eu usei a abordagem Duncan C, corrigi alguns erros que ele cometeu
-(NSInteger) daysBetweenDate:(NSDate *)firstDate andDate:(NSDate *)secondDate {
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
NSDateComponents *components = [currentCalendar components: NSDayCalendarUnit fromDate: firstDate toDate: secondDate options: 0];
NSInteger days = [components day];
return days;
}
Eu uso este pequeno método utilizado:
-(NSDate*)normalizedDateWithDate:(NSDate*)date
{
NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate: date];
return [calendar_ dateFromComponents:components]; // NB calendar_ must be initialized
}
(Você obviamente precisa ter um adar chamado calendar_
contendo um NSCalendar
.)
Usando isso, é fácil verificar se uma data é hoje assim:
[[self normalizeDate:aDate] isEqualToDate:[self normalizeDate:[NSDate date]]];
([NSDate date]
Retorna a data e a hora atuais.)
É claro que isso é muito semelhante ao que Gregory sugere. A desvantagem dessa abordagem é que ela tende a criar muitos NSDate
objetos. Se você vai processar muitas datas, eu recomendaria usar outro método, como comparar os componentes diretamente ou trabalhar com NSDateComponents
objetos em vez de NSDates
.
A resposta é mais simples do que todo mundo faz com que seja. NScalendar tem um método
components:fromDate:toDate:options
Esse método permite calcular a diferença entre duas datas usando as unidades que desejar.
Então escreva um método como este:
-(NSInteger) daysBetweenDate: (NSDate *firstDate) andDate: (NSDate *secondDate)
{
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
NSDateComponents components* = [currentCalendar components: NSDayCalendarUnit
fromDate: firstDate
toDate: secondDate
options: 0];
NSInteger days = [components days];
return days;
}
Se o método acima retornar zero, as duas datas estarão no mesmo dia.
A partir do iOS 8.0, você pode usar:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSComparisonResult dateComparison = [calendar compareDate:[NSDate date] toDate:otherNSDate toUnitGranularity:NSCalendarUnitDay];
Se o resultado for, por exemplo, NSODERdeDDescending, o outro date está antes [da data do NSDATE] em termos de dias.
Eu não vejo esse método na documentação do NSCalendar, mas está no IOS 7.1 para iOS 8.0 Diferenças da API
Para desenvolvedores codificando em Swift 3
if(NSCalendar.current.isDate(selectedDate, inSameDayAs: NSDate() as Date)){
// Do something
}
Com Swift 3, de acordo com as suas necessidades, você pode escolher um dos seguintes padrões, a fim de resolver o seu problema.
#1.Usando compare(_:to:toGranularity:)
método
Calendar
tem um método chamado compare(_:to:toGranularity:)
. compare(_:to:toGranularity:)
tem a seguinte declaração:
func compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResult
Compara as datas dadas para baixo para o componente indicado, informando
orderedSame
se eles são os mesmos de um dado componente e todos os componentes maiores, caso contrário, qualquerorderedAscending
ouorderedDescending
.
O Parque de código abaixo mostra a quente utilizar:
import Foundation
let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"
/* Compare date1 and date2 */
do {
let comparisonResult = calendar.compare(date1, to: date2, toGranularity: .day)
switch comparisonResult {
case ComparisonResult.orderedSame:
print("Same day")
default:
print("Not the same day")
}
// Prints: "Not the same day"
}
/* Compare date1 and date3 */
do {
let comparisonResult = calendar.compare(date1, to: date3, toGranularity: .day)
if case ComparisonResult.orderedSame = comparisonResult {
print("Same day")
} else {
print("Not the same day")
}
// Prints: "Same day"
}
#2.Usando dateComponents(_:from:to:)
Calendar
tem um método chamado dateComponents(_:from:to:)
. dateComponents(_:from:to:)
tem a seguinte declaração:
func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents
Retorna a diferença entre duas datas.
O Parque de código abaixo mostra a quente utilizar:
import Foundation
let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"
/* Compare date1 and date2 */
do {
let dateComponents = calendar.dateComponents([.day], from: date1, to: date2)
switch dateComponents.day {
case let value? where value < 0:
print("date2 is before date1")
case let value? where value > 0:
print("date2 is after date1")
case let value? where value == 0:
print("date2 equals date1")
default:
print("Could not compare dates")
}
// Prints: date2 is before date1
}
/* Compare date1 and date3 */
do {
let dateComponents = calendar.dateComponents([.day], from: date1, to: date3)
switch dateComponents.day {
case let value? where value < 0:
print("date2 is before date1")
case let value? where value > 0:
print("date2 is after date1")
case let value? where value == 0:
print("date2 equals date1")
default:
print("Could not compare dates")
}
// Prints: date2 equals date1
}
int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24);
if (interval!=0){
//not the same day;
}
Minha solução foi duas conversões com o nsdateFormatter:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyyMMdd"];
[dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
NSDate *today = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *todayString=[dateFormat stringFromDate:today];
NSDate *todayWithoutHour=[dateFormat dateFromString:todayString];
if ([today compare:exprDate] == NSOrderedDescending)
{
//do
}
A documentação sobre Nsdate indica que o compare:
e isEqual:
Os métodos executarão uma comparação básica e ordenarão os resultados, embora ainda sejam considerados no tempo.
Provavelmente a maneira mais simples de gerenciar a tarefa seria criar um novo isToday
Método para o efeito do seguinte:
- (bool)isToday:(NSDate *)otherDate
{
currentTime = [however current time is retrieved]; // Pardon the bit of pseudo-code
if (currentTime < [otherDate timeIntervalSinceNow])
{
return YES;
}
else
{
return NO;
}
}
Este é um gato particularmente feio para a pele, mas aqui está outra maneira de fazê -lo. Não digo que é elegante, mas provavelmente é o mais próximo que você pode obter com o suporte a data/hora no iOS.
bool isToday = [[NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle] isEqualToString:[NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle]];
NSUInteger unit = NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit;
NSDateComponents *comp = [cal components:unit
fromDate:nowDate
toDate:setDate
options:0];
NSString *dMonth;
dMonth = [NSString stringWithFormat:@"%02ld",comp.month];
NSString *dDay;
dDay = [NSString stringWithFormat:@"%02ld",comp.day + (comp.hour > 0 ? 1 : 0)];
Compare a hora também para corrigir a diferença de 1 dia