Làm thế nào để so sánh hai NSDates: Cái nào gần đây hơn?


244

Tôi đang cố gắng để đạt được đồng bộ hóa dropBox và cần so sánh ngày của hai tệp. Một là trên tài khoản dropBox của tôi và một là trên iPhone của tôi.

Tôi đã đưa ra những điều sau đây, nhưng tôi nhận được kết quả bất ngờ. Tôi đoán tôi đang làm gì đó sai về cơ bản khi so sánh hai ngày. Tôi chỉ đơn giản sử dụng các toán tử> <, nhưng tôi đoán điều này không tốt vì tôi đang so sánh hai chuỗi NSDate. Ở đây chúng tôi đi:

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.");
}

Điều này đã cho tôi đầu ra (ngẫu nhiên & sai) sau đây:

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.

hoặc điều này xảy ra là chính xác:

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
Bản sao: 1 2 3 4 5 6 & c.
jscs

1
@JoshCaswell nếu đó là một bản sao thực sự, tại sao không hợp nhất chúng? Bạn đã làm điều đó trước khi ...
Dan Rosenstark

1
Chỉ người điều hành kim cương mới có thể thực hiện hợp nhất, @Yar.
jscs

Câu trả lời:


658

Giả sử hai ngày:

NSDate *date1;
NSDate *date2;

Sau đó, so sánh sau đây sẽ cho biết cái nào sớm hơn / muộn hơn / giống nhau:

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");
}

Vui lòng tham khảo tài liệu lớp NSDate để biết thêm chi tiết.


Đáng yêu! Nhịp đập lộn xộn với [date1 sớm hơn Ngày: date2] vv ... Cảm ơn - vì một số lý do tôi chưa bao giờ nghĩ sẽ sử dụng so sánh: trước đây.
SomaMan

11
Tôi thích dựa vào thực tế là NSOrderedAsceinating <0 và NSOrderedDesceinating> 0. Điều đó làm cho phép so sánh dễ đọc hơn: [date1 so sánh: date2] <0 / * date1 <date2 * / và tránh lỗi (dễ thực hiện) @albertamg chỉ ra. ;-)
jpap

Chà - phương pháp so sánh dễ bị lỗi như lỗi do lỗi một. Vì vậy, bạn nên sử dụng (NSDate *) laterDate: (NSDate *) otherDate sẽ trả về ngày sau của cả hai. vì vậy bạn chỉ cần so sánh kết quả mong đợi của bạn và bạn đã hoàn tất! Không loay hoay với "Waaait giảm dần / tăng dần ?!"
Masi

@jpap Điều đó cũng làm tôi bực mình; có vẻ như Apple muốn bạn nghĩ về kết quả date1 -> date2tăng dần / giảm dần (và do đó date1 là muộn hơn hoặc sớm hơn).
Ja͢ck

@Jack đó là một cách trừu tượng hơn mà không cần số ma thuật (-1,0,1) để sắp xếp các thuật toán để sắp xếp các phần tử theo thứ tự. Bạn cũng có thể tự xác định lại các hằng số đó với một tên dễ đọc hơn. Câu trả lời của tôi là thực hiện công việc nhưng không phải là người chiến thắng giải thưởng về mã có thể đọc được. Cuộn xuống, có những cái tốt khác.
Nick Weaver

50

Đến bữa tiệc muộn, nhưng một cách dễ dàng khác để so sánh các đối tượng NSDate là chuyển đổi chúng thành các kiểu nguyên thủy cho phép sử dụng dễ dàng '>' '<' '==', v.v.

ví dụ.

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

timeIntervalSinceReferenceDatechuyển đổi ngày thành giây kể từ ngày tham chiếu (ngày 1 tháng 1 năm 2001, GMT). Khi timeIntervalSinceReferenceDatetrả về một NSTimeInterval (là một typedef kép), chúng ta có thể sử dụng các bộ so sánh nguyên thủy.


4
Hơi trực quan hơn một chút (NSComparisonResult)compare:(NSDate *)nhưng vẫn khá dài dòng cho thao tác đơn giản này ... (như thường lệ)
Pierre de LESPINAY 04/07 '

1
cũng có thể làm[dateA timeIntervalSinceDate:dateB] > 0
Scott Fister

14

Trong Swift, bạn có thể quá tải các toán tử hiện có:

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

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

Sau đó, bạn có thể so sánh trực tiếp với NSDates <, >==(đã được hỗ trợ).


Nếu tôi cố gắng thực hiện một phần mở rộng ra khỏi điều này, tôi nhận được "Toán tử chỉ được phép ở phạm vi toàn cầu", đề xuất?
JohnVanDijk

@JohnVanDijk bạn không thể đặt nó trong một phần mở rộng. Tôi sẽ đặt nó trong cùng một tệp với phần mở rộng, nhưng bên ngoài{ ... }
Andrew

13

NSDate có chức năng so sánh.

compare:Trả về một NSComparisonResultgiá trị chỉ ra thứ tự tạm thời của người nhận và một ngày cụ thể khác.

(NSComparisonResult)compare:(NSDate *)anotherDate

Thông số : anotherDate Ngày để so sánh người nhận. Giá trị này không được bằng không. Nếu giá trị bằng 0, hành vi không được xác định và có thể thay đổi trong các phiên bản tương lai của Mac OS X.

Giá trị trả về:

  • Nếu người nhận và người khác chính xác bằng nhau, NSOrderedSame
  • Nếu người nhận đến muộn hơn thời gian khác, NSOrderedDescending
  • Nếu người nhận đến sớm hơn thời gian khác NSOrderedAscending.

@Irene có cách nào để so sánh hai đối tượng NSDate trong đó chỉ có thành phần thời gian là khác nhau? Vì một số lý do, phương pháp trên không hoạt động.
ThE uSeFuL

12

Bạn muốn sử dụng các phương thức so sánh NSDate:, laterDate:, trướcDate:, hoặc isEqualToDate :. Sử dụng toán tử <và> trong tình huống này là so sánh các con trỏ, không phải ngày


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

Điều này trả về trước đó của người nhận và otherDate. Nếu cả hai đều giống nhau, người nhận được trả lại.


1
Lưu ý rằng đối tượng sao lưu của NSDates có thể được tối ưu hóa trên các phiên bản 64 bit của mã được biên dịch của bạn sao cho các ngày biểu thị cùng thời gian sẽ có cùng địa chỉ. Như vậy nếu cDate = [aDate earlierDate:bDate]sau đó cDate == aDatecDate == bDatecả hai có thể đúng. Tìm thấy điều này khi thực hiện một số công việc ngày trên iOS 8.
Ben Flynn

1
Ngược lại, trên nền tảng 32 bit, nếu ngày không giống nhau, -earlierDate:(và -laterDate:) có thể trả về cả người nhận và đối số.
Ben Lings

7

Một số tiện ích ngày, bao gồm so sánh IN ENGLISH, rất hay:

#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

Việc thực hiện:

#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
Hoặc chỉ sử dụng: github.com/erica/NSDate-Extensions
Dan Rosenstark


6

Bạn nên sử dụng :

- (NSComparisonResult)compare:(NSDate *)anotherDate

để so sánh ngày. Không có toán tử quá tải trong mục tiêu C.


6

Tại sao các bạn không sử dụng các NSDatephương pháp so sánh này :

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

4

Tôi đã gặp tình huống gần như tương tự, nhưng trong trường hợp của tôi, tôi đang kiểm tra xem số ngày có chênh lệch không

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.

Hữu ích khi bạn cần so sánh NSDate theo đơn vị Ngày / Tháng / Năm


NSDayCalWikiUnit không được dùng nữa, vì vậy hãy sử dụng NSCalWikiUnitDay
Mazen Kasser

2

Bạn cũng có thể so sánh hai ngày bằng phương pháp này

        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

Tôi đã thử nó hy vọng nó hoạt động cho bạn

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

Sử dụng chức năng đơn giản này để so sánh ngày

-(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;}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.