Як порівняти два 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 & c.
jscs

1
@JoshCaswell, якщо це справжній дублікат, чому б не злити їх? Ви робили це раніше ...
Дан Розенстарк

1
Лише модератори алмазів можуть виконувати злиття, @Yar.
jscs

Відповіді:


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 .


Прекрасна! Удари возиться з [date1 ранішеDate: date2] тощо ... Спасибі - чомусь я ніколи не думав використовувати порівняння: раніше.
SomaMan

11
Мені подобається покладатися на те, що NSOrderedAscending <0 і NSOrderedDescending> 0. Це полегшує читання порівняння: [date1 порівняти: date2] <0 / * date1 <date2 * / і уникає (легко зробити) помилку @albertamg зазначив. ;-)
jpap

Ну - метод порівняння настільки ж схильний до помилок, як і помилки окремо. Таким чином, ви повинні використовувати (NSDate *) laterDate: (NSDate *) anotherDate, який поверне пізнішу дату обох. тож ви просто порівняєте очікуваний результат, і все закінчено! Ніякого не обманюючи з "Waaait низхід / сходження ?!"
masi

@jpap Це також зіпсувало мене; здається, що Apple хоче, щоб ви думали про результат як про date1 -> date2зростаючому / спадному (і тому дата1 пізніше чи раніше).
Ja͢ck

@Jack - це більш абстрактний спосіб без магічних чисел (-1,0,1) для сортування алгоритмів для наведення елементів у порядок. Ви також можете переосмислити ці константи з більш читабельною назвою. Моя відповідь виконує завдання, але не є переможцем за читабельний код. Прокрутіть вниз, є й інші хороші.
Нік Вівер

50

Пізно до партії, але ще одним простим способом порівняння об’єктів NSDate є перетворення їх у примітивні типи, що дозволяє легко використовувати '>' '<' '==' тощо

напр.

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

timeIntervalSinceReferenceDateперетворює дату в секунди з моменту опорної дати (1 січня 2001 р., GMT). Як timeIntervalSinceReferenceDateповертає NSTimeInterval (який є подвійним typedef), ми можемо використовувати примітивні компаратори.


4
Трохи інтуїтивніше, (NSComparisonResult)compare:(NSDate *)але все ж досить багатослівне для цієї простої операції ... (як завжди)
П'єр де ЛЕСПІНАЙ

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 дата порівняння приймача. Це значення не повинно бути нульовим. Якщо значення є нульовим, поведінка не визначена і може змінюватися в майбутніх версіях Mac OS X.

Повернене значення:

  • Якщо приймач та іншийДата точно однакові, NSOrderedSame
  • Якщо приймач пізніше, ніж іншийДата, NSOrderedDescending
  • Якщо приймач раніше в часі , ніж anotherDate, NSOrderedAscending.

@Irene Чи існує спосіб порівняння двох об'єктів NSDate, у яких відрізняється лише часова складова? Чомусь вищевказаний метод не працює.
ТЕ uSeFuL

12

Ви хочете скористатися методами порівняння NSDate :, пізнішеDate :, ранішеDate:, або isEqualToDate:. Використання операторів <і> в цій ситуації порівнює вказівники, а не дати


11
- (NSDate *)earlierDate:(NSDate *)anotherDate

Це повертає попередній прийом приймача та іншогоДати. Якщо обидва однакові, приймач повертається.


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
Dan Rosenstark


6

Ви повинні використовувати:

- (NSComparisonResult)compare:(NSDate *)anotherDate

для порівняння дат. Немає перевантаження оператора в об'єктиві C.


6

Чому ви не скористаєтесь цими NSDateметодами порівняння:

- (NSDate *)earlierDate:(NSDate *)anotherDate;
- (NSDate *)laterDate:(NSDate *)anotherDate;

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 замість
Мазен Кассер

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];

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;}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.