วิธีการเปรียบเทียบสอง NSDates: ไหนล่าสุด?


244

ฉันกำลังพยายามทำให้การซิงก์ 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 หากซ้ำกันจริง ๆ ทำไมไม่รวมพวกเขาเข้าด้วยกัน คุณเคยทำมาก่อน ...
Dan Rosenstark

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 ก่อนหน้านี้วันที่: date2] ฯลฯ ... ขอบคุณ - ด้วยเหตุผลบางอย่างฉันไม่เคยคิดที่จะใช้การเปรียบเทียบ: ก่อน
SomaMan

11
ฉันชอบที่จะพึ่งพาความจริงที่ว่า NSOrderedAscending <0 และ NSOrderedDescending> 0 ซึ่งทำให้การเปรียบเทียบง่ายต่อการอ่าน: [date1 เปรียบเทียบ: date2] <0 / * date1 <date2 * / และหลีกเลี่ยงความผิดพลาด @albertamg ชี้ให้เห็น. ;-)
jpap

ดี - วิธีการเปรียบเทียบเป็นข้อผิดพลาดได้ง่ายเช่นเดียวกับข้อผิดพลาดแบบหนึ่งต่อหนึ่ง ดังนั้นคุณควรใช้ (NSDate *) laterDate: (NSDate *) anotherDate ซึ่งจะส่งคืนวันที่ในภายหลังของทั้งคู่ ดังนั้นคุณเพียงแค่เปรียบเทียบผลลัพธ์ที่คาดหวังของคุณและคุณทำเสร็จแล้ว! ไม่ต้องไปยุ่งกับ "Waaait จากน้อยไปมาก / มากไปหาน้อย!"
masi

@ jpap นั่นทำให้ฉันยุ่งเช่นกัน ดูเหมือนว่าแอปเปิ้ลต้องการให้คุณคิดว่าผลลัพธ์date1 -> date2จะขึ้น / ลง (ดังนั้นวันที่ 1 จะช้ากว่าหรือเร็วกว่าตามลำดับ)
Ja͢ck

@ แจ็คมันเป็นวิธีที่เป็นนามธรรมมากขึ้นโดยไม่ต้องมีหมายเลขเวทย์มนตร์ (-1,0,1) สำหรับการเรียงลำดับอัลกอริธึมเพื่อวางองค์ประกอบตามลำดับ คุณสามารถกำหนดค่าคงที่เหล่านั้นด้วยตัวเองด้วยชื่อที่อ่านง่ายขึ้น คำตอบของฉันทำงานอยู่ แต่ไม่ใช่ผู้ชนะรางวัลรหัสที่อ่านได้ เลื่อนลงมามีคนดีอีกหลายคน
Nick Weaver

50

ไปงานปาร์ตี้สาย แต่วิธีที่ง่ายอีกวิธีหนึ่งในการเปรียบเทียบวัตถุ NSDate คือการแปลงให้เป็นประเภทดั้งเดิมซึ่งช่วยให้ใช้งานได้ง่าย '>' '<' '==' ฯลฯ

เช่น.

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

timeIntervalSinceReferenceDateแปลงวันที่เป็นวินาทีตั้งแต่วันที่อ้างอิง (1 มกราคม 2544, GMT) ในฐานะที่เป็นtimeIntervalSinceReferenceDateผลตอบแทน NSTimeInterval (ซึ่งเป็น typedef คู่) เราสามารถใช้ comparators ดั้งเดิม


4
ใช้งานง่ายกว่าเล็กน้อย(NSComparisonResult)compare:(NSDate *)แต่ก็ยังค่อนข้างละเอียดสำหรับการใช้งานง่ายนี้ ... (ตามปกติ)
Pierre de LESPINAY

1
ยังสามารถทำได้[dateA timeIntervalSinceDate:dateB] > 0
Scott Fister

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 คุณไม่สามารถใส่ไว้ในส่วนขยายได้ ฉันจะใส่ไว้ในไฟล์เดียวกับนามสกุล แต่ข้างนอก{ ... }
Andrew

13

NSDate มีฟังก์ชั่นเปรียบเทียบ

compare:ส่งคืนNSComparisonResultค่าที่ระบุการสั่งซื้อชั่วคราวของผู้รับและวันที่อื่น

(NSComparisonResult)compare:(NSDate *)anotherDate

พารามิเตอร์ : anotherDate วันที่ที่จะเปรียบเทียบผู้รับ ค่านี้ต้องไม่เป็นศูนย์ หากค่าเป็นศูนย์พฤติกรรมจะไม่ได้กำหนดและอาจมีการเปลี่ยนแปลงในรุ่นอนาคตของ Mac OS X

มูลค่าส่งคืน:

  • หากผู้รับและอีกวันที่เท่ากับกัน NSOrderedSame
  • หากเครื่องรับช้ากว่าวันอื่น NSOrderedDescending
  • หากผู้รับเร็วกว่าเวลาอื่นวันที่, NSOrderedAscending.

@ Irene มีวิธีการเปรียบเทียบสองวัตถุ NSDate ซึ่งมีเพียงองค์ประกอบเวลาแตกต่างกันอย่างไร ด้วยเหตุผลบางอย่างวิธีการข้างต้นไม่ทำงาน
ประโยชน์

12

คุณต้องการใช้การเปรียบเทียบ NSDate:, laterDate:, beforeDate :, หรือ isEqualToDate: เมธอด การใช้ตัวดำเนินการ <และ> ในสถานการณ์นี้เป็นการเปรียบเทียบตัวชี้ไม่ใช่วันที่


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

สิ่งนี้จะคืนค่าก่อนหน้าของผู้รับและวันอื่น หากทั้งคู่เหมือนกันผู้รับจะถูกส่งคืน


1
โปรดทราบว่าออบเจ็กต์สำรองของ NSDates อาจได้รับการปรับให้เหมาะสมกับโค้ดที่คอมไพล์ของคุณเวอร์ชั่น 64 บิตซึ่งวันที่ที่แสดงเวลาเดียวกันจะมีที่อยู่เดียวกัน ดังนั้นถ้าเป็นเช่นcDate = [aDate earlierDate:bDate]นั้นcDate == aDateและcDate == bDateสามารถเป็นจริงได้ทั้งคู่ พบว่าสิ่งนี้กำลังทำงานใน iOS 8
Ben Flynn

1
ในทางกลับกันบนแพลตฟอร์ม 32 บิตหากวันที่ไม่เหมือนกัน-earlierDate:(และ-laterDate:) สามารถส่งคืนทั้งผู้รับและอาร์กิวเมนต์
Ben Lings

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- ส่วนขยาย
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 แทน
Mazen 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];

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;}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.