Как сравнить два NSDates: что является более поздним?

244

Я пытаюсь добиться синхронизации DropBox и мне нужно сравнить даты двух файлов. Один на моем аккаунте dropBox, а другой на моем iPhone.

Я придумал следующее, но получаю неожиданные результаты. Я думаю, что я делаю что-то в корне неправильно, сравнивая две даты. Я просто использовал операторы> <, но, думаю, это не очень хорошо, так как я сравниваю две строки NSDate. Вот так:

NSLog(@"dB...lastModified: %@", dbObject.lastModifiedDate); 
NSLog(@"iP...lastModified: %@", [self getDateOfLocalFile:@"NoteBook.txt"]);

if ([dbObject lastModifiedDate] < [self getDateOfLocalFile:@"NoteBook.txt"]) {
    NSLog(@"...db is more up-to-date. Download in progress...");
    [self DBdownload:@"NoteBook.txt"];
    NSLog(@"Download complete.");
} else {
    NSLog(@"...iP is more up-to-date. Upload in progress...");
    [self DBupload:@"NoteBook.txt"];
    NSLog(@"Upload complete.");
}

Это дало мне следующий (случайный и неправильный) вывод:

2011-05-11 14:20:54.413 NotePage[6918:207] dB...lastModified: 2011-05-11 13:18:25 +0000
2011-05-11 14:20:54.414 NotePage[6918:207] iP...lastModified: 2011-05-11 13:20:48 +0000
2011-05-11 14:20:54.415 NotePage[6918:207] ...db is more up-to-date.

или этот, который оказывается правильным:

2011-05-11 14:20:25.097 NotePage[6903:207] dB...lastModified: 2011-05-11 13:18:25 +0000
2011-05-11 14:20:25.098 NotePage[6903:207] iP...lastModified: 2011-05-11 13:19:45 +0000
2011-05-11 14:20:25.099 NotePage[6903:207] ...iP is more up-to-date.
неважно
источник
11
Дубликаты: 1 2 3 4 5 6 и с.
ОАО
1
@JoshCaswell, если это настоящий дубликат, почему бы не объединить их? Вы сделали это раньше ...
Дэн Розенстарк
1
Только алмазные модераторы могут выполнять слияние, @ Яр.
ОАО

Ответы:

658

Давайте предположим две даты:

NSDate *date1;
NSDate *date2;

Тогда следующее сравнение покажет, что раньше / позже / то же самое:

if ([date1 compare:date2] == NSOrderedDescending) {
    NSLog(@"date1 is later than date2");
} else if ([date1 compare:date2] == NSOrderedAscending) {
    NSLog(@"date1 is earlier than date2");
} else {
    NSLog(@"dates are the same");
}

Пожалуйста, обратитесь к документации класса NSDate для более подробной информации.

Ник Уивер
источник
Прекрасный! Beats возиться с [date1 ранееDate: date2] и т.д ... Спасибо - по какой-то причине я никогда не думал использовать сравнение: раньше.
SomaMan
11
Мне нравится полагаться на тот факт, что NSOrderedAscending <0 и NSOrderedDescending> 0. Это упрощает сравнение: [date1 сравни: date2] <0 / * date1 <date2 * / и позволяет избежать (легко сделать) ошибки @albertamg указал. ;-)
jpap
Что ж, метод сравнения так же подвержен ошибкам, как и отдельные ошибки. Таким образом, вы должны использовать (NSDate *) LaterDate: (NSDate *) anotherDate, которая будет возвращать более позднюю дату обоих. так что вы просто сравниваете ожидаемый результат и все готово! Нет возиться с "Waaait по убыванию / по возрастанию?!"
Маси
@jpap Это меня тоже запутало; похоже, что Apple хочет, чтобы вы думали о результате как о date1 -> date2восходящем / нисходящем (и, следовательно, date1 - позже или раньше соответственно).
Ja͢ck
@Jack - это более абстрактный способ без магических чисел (-1,0,1) для сортировки алгоритмов, чтобы упорядочить элементы. Вы также можете сами переопределить эти константы с более читаемым именем. Мой ответ делает работу, но не является лауреатом премии за читаемый код. Прокрутите вниз, есть и другие хорошие.
Ник Уивер
50

Позднее, но другой простой способ сравнения объектов NSDate - преобразовать их в примитивные типы, что позволяет легко использовать '>' '<' '==' и т. Д.

например.

if ([dateA timeIntervalSinceReferenceDate] > [dateB timeIntervalSinceReferenceDate]) {
    //do stuff
}

timeIntervalSinceReferenceDateпреобразует дату в секунды после отчетной даты (1 января 2001 года, время по Гринвичу). Так как timeIntervalSinceReferenceDateвозвращает NSTimeInterval (который является двойной typedef), мы можем использовать примитивные компараторы.

Так над этим
источник
4
Немного более интуитивно, чем, (NSComparisonResult)compare:(NSDate *)но все же довольно многословно для этой простой операции ... (как обычно)
Pierre de LESPINAY
1
можно также сделать[dateA timeIntervalSinceDate:dateB] > 0
Скотт Фистер
14

В Swift вы можете перегрузить существующих операторов:

func > (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.timeIntervalSinceReferenceDate > rhs.timeIntervalSinceReferenceDate
}

func < (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.timeIntervalSinceReferenceDate < rhs.timeIntervalSinceReferenceDate
}

Затем вы можете сравнить NSDates непосредственно <, >и ==(уже поддерживается).

Андрей
источник
Если я пытаюсь сделать из этого расширение, я получаю «Операторы разрешены только в глобальном масштабе», предложения?
JohnVanDijk
@JohnVanDijk вы не можете поместить его в расширение. Я бы положил его в тот же файл, что и расширение, но за пределами{ ... }
Андрей
13

NSDate имеет функцию сравнения.

compare:Возвращает NSComparisonResultзначение, которое указывает временное упорядочение получателя и другую заданную дату.

(NSComparisonResult)compare:(NSDate *)anotherDate

Параметры : anotherDate дата, с которой сравнивается получатель. Это значение не должно быть равно нулю. Если значение равно nil, поведение не определено и может измениться в будущих версиях Mac OS X.

Возвращаемое значение:

  • Если получатель и anotherDate точно равны друг другу, NSOrderedSame
  • Если получатель позже, чем другой день, NSOrderedDescending
  • Если получатель раньше времени, чем другая дата NSOrderedAscending.
Gary
источник
@ Ирэн, есть ли способ сравнить два объекта NSDate, в которых отличается только временной компонент? По какой-то причине вышеуказанный метод не работает.
ИСПОЛЬЗУЕТСЯ
12

Вы хотите использовать методы сравнения NSDate :, LaterDate :, earlyDate: или isEqualToDate:. Использование операторов <и> в этой ситуации сравнивает указатели, а не даты

Дэн Ф
источник
11
- (NSDate *)earlierDate:(NSDate *)anotherDate

Это возвращает более раннюю версию получателя и anotherDate. Если оба одинаковы, получатель возвращается.

Maulik
источник
1
Обратите внимание, что базовый объект NSDates может быть оптимизирован в 64-битных версиях вашего скомпилированного кода, так что даты, представляющие одно и то же время, будут иметь один и тот же адрес. Таким образом, если cDate = [aDate earlierDate:bDate]тогда cDate == aDateи то и cDate == bDateдругое может быть правдой. Я нашел это, работая над iOS 8
Бен Флинн
1
И наоборот, на 32-битных платформах, если даты не совпадают, -earlierDate:-laterDate:) не может вернуть ни получателя, ни аргумента.
Бен Линс
7

Некоторые утилиты даты, в том числе сравнения на английском языке, что приятно:

#import <Foundation/Foundation.h>


@interface NSDate (Util)

-(BOOL) isLaterThanOrEqualTo:(NSDate*)date;
-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date;
-(BOOL) isLaterThan:(NSDate*)date;
-(BOOL) isEarlierThan:(NSDate*)date;
- (NSDate*) dateByAddingDays:(int)days;

@end

Реализация:

#import "NSDate+Util.h"


@implementation NSDate (Util)

-(BOOL) isLaterThanOrEqualTo:(NSDate*)date {
    return !([self compare:date] == NSOrderedAscending);
}

-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date {
    return !([self compare:date] == NSOrderedDescending);
}
-(BOOL) isLaterThan:(NSDate*)date {
    return ([self compare:date] == NSOrderedDescending);

}
-(BOOL) isEarlierThan:(NSDate*)date {
    return ([self compare:date] == NSOrderedAscending);
}

- (NSDate *) dateByAddingDays:(int)days {
    NSDate *retVal;
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setDay:days];

    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    retVal = [gregorian dateByAddingComponents:components toDate:self options:0];
    return retVal;
}

@end
Дэн Розенстарк
источник
1
Или просто используйте: github.com/erica/NSDate-Extensions
Дэн Розенстарк
6

Вы должны использовать:

- (NSComparisonResult)compare:(NSDate *)anotherDate

сравнивать даты. В задаче С. перегрузка операторов отсутствует.

Йорис Манс
источник
6

Почему бы вам не использовать эти NSDateметоды сравнения:

- (NSDate *)earlierDate:(NSDate *)anotherDate;
- (NSDate *)laterDate:(NSDate *)anotherDate;
justicepenny
источник
4

Я сталкиваюсь с почти такой же ситуацией, но в моем случае я проверяю разницу в количестве дней

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *compDate = [cal components:NSDayCalendarUnit fromDate:fDate toDate:tDate options:0];
int numbersOfDaysDiff = [compDate day]+1; // do what ever comparison logic with this int.

Полезно, когда вам нужно сравнить NSDate в единицах Дни / Месяц / Год

Энди
источник
NSDayCalendarUnit устарел, поэтому используйте вместо него NSCalendarUnitDay
Kasser
2

Вы можете сравнить две даты этим методом также

        switch ([currenttimestr  compare:endtimestr])
        {
            case NSOrderedAscending:

                // dateOne is earlier in time than dateTwo
                break;

            case NSOrderedSame:

                // The dates are the same
                break;
            case NSOrderedDescending:

                // dateOne is later in time than dateTwo


                break;

        }
Капил
источник
0

Я попробовал это надеюсь, что это работает для вас

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];      
int unitFlags =NSDayCalendarUnit;      
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];     
NSDate *myDate; //= [[NSDate alloc] init];     
[dateFormatter setDateFormat:@"dd-MM-yyyy"];   
myDate = [dateFormatter dateFromString:self.strPrevioisDate];     
NSDateComponents *comps = [gregorian components:unitFlags fromDate:myDate toDate:[NSDate date] options:0];   
NSInteger day=[comps day];
Концепция Infoway
источник
0

Используйте эту простую функцию для сравнения дат

-(BOOL)dateComparision:(NSDate*)date1 andDate2:(NSDate*)date2{

BOOL isTokonValid;

if ([date1 compare:date2] == NSOrderedDescending) {
    NSLog(@"date1 is later than date2");
    isTokonValid = YES;
} else if ([date1 compare:date2] == NSOrderedAscending) {
    NSLog(@"date1 is earlier than date2");
    isTokonValid = NO;
} else {
    isTokonValid = NO;
    NSLog(@"dates are the same");
}

return isTokonValid;}
Ахтар
источник