Bagaimana membandingkan dua NSDates: Mana yang lebih baru?

244

Saya mencoba mencapai sinkronisasi dropBox dan perlu membandingkan tanggal dari dua file. Satu ada di akun dropBox saya dan satu lagi di iPhone saya.

Saya datang dengan yang berikut ini, tetapi saya mendapatkan hasil yang tidak terduga. Saya kira saya melakukan sesuatu yang secara fundamental salah ketika membandingkan kedua tanggal. Saya hanya menggunakan> <operator, tetapi saya kira ini tidak baik karena saya membandingkan dua string NSDate. Kita mulai:

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

Ini memberi saya output (acak & salah) berikut:

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.

atau yang ini ternyata benar:

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.
lupakan
sumber
11
Duplikat: 1 2 3 4 5 6 & c.
jscs
1
@ JoshCaswell jika itu duplikat nyata, mengapa tidak menggabungkannya? Anda pernah melakukannya sebelumnya ...
Dan Rosenstark
1
Hanya moderator berlian yang dapat melakukan penggabungan, @Yar.
jscs

Jawaban:

658

Mari kita asumsikan dua tanggal:

NSDate *date1;
NSDate *date2;

Kemudian perbandingan berikut akan memberi tahu mana yang lebih dulu / lebih baru / sama:

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

Silakan merujuk ke dokumentasi kelas NSDate untuk lebih jelasnya.

Nick Weaver
sumber
Menyenangkan! Ketukan mengotak-atik dengan [date1 sebelumnya Tanggal: date2] dll ... Terima kasih - untuk beberapa alasan saya tidak pernah berpikir untuk menggunakan bandingkan: sebelumnya.
SomaMan
11
Saya suka mengandalkan fakta bahwa NSOrderedAscending <0 dan NSOrderedDescending> 0. Itu membuat perbandingan lebih mudah dibaca: [date1 bandingkan: date2] <0 / * date1 <date2 * / dan menghindari kesalahan (mudah dibuat) @albertamg ditunjukkan. ;-)
jpap
Yah - metode perbandingannya rawan kesalahan sama seperti kesalahan satu-per-satu. Dengan demikian, Anda harus menggunakan (NSDate *) laterDate: (NSDate *) anotherDate yang akan mengembalikan tanggal nanti dari keduanya. jadi Anda hanya membandingkan hasil yang diharapkan dan selesai! Tidak bermain-main dengan "Waaait turun / naik?!"
masi
@ jpap Itu mengacaukan saya juga; tampaknya Apple ingin Anda memikirkan hasilnya sebagai date1 -> date2naik / turun (dan oleh karena itu date1 lebih lambat atau lebih awal masing-masing).
Ja͢ck
@Jack, ini adalah cara yang lebih abstrak tanpa angka ajaib (-1,0,1) untuk menyortir algoritma untuk mengatur elemen. Anda juga dapat mendefinisikan kembali konstanta-konstanta itu dengan nama yang lebih mudah dibaca. Jawaban saya adalah melakukan pekerjaan tetapi bukan pemenang penghargaan kode yang dapat dibaca. Gulir ke bawah, ada yang bagus.
Nick Weaver
50

Terlambat ke pesta, tetapi cara mudah lain untuk membandingkan objek NSDate adalah dengan mengubahnya menjadi tipe primitif yang memungkinkan penggunaan mudah '>' '<' '==' dll.

misalnya.

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

timeIntervalSinceReferenceDatemengubah tanggal menjadi detik sejak tanggal referensi (1 Januari 2001, GMT). Sebagai timeIntervalSinceReferenceDatemengembalikan NSTimeInterval (yang merupakan typedef ganda), kita dapat menggunakan komparator primitif.

Jadi Over It
sumber
4
Sedikit lebih intuitif daripada (NSComparisonResult)compare:(NSDate *)tetapi masih cukup bertele-tele untuk operasi sederhana ini ... (seperti biasa)
Pierre de LESPINAY
1
juga dapat melakukannya[dateA timeIntervalSinceDate:dateB] > 0
Scott Fister
14

Di Swift, Anda dapat membebani operator yang ada:

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

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

Kemudian, Anda dapat membandingkan NSDates langsung dengan <, >, dan ==(sudah didukung).

Andrew
sumber
Jika saya mencoba membuat ekstensi dari ini, saya mendapatkan "Operator hanya diperbolehkan pada lingkup global", saran?
JohnVanDijk
@JohnVanDijk Anda tidak bisa memasukkannya ke dalam ekstensi. Saya akan meletakkannya di file yang sama dengan ekstensi, tetapi di luar{ ... }
Andrew
13

NSDate memiliki fungsi bandingkan.

compare: Mengembalikan sebuah NSComparisonResult nilai yang menunjukkan pemesanan sementara penerima dan tanggal lain yang diberikan.

(NSComparisonResult)compare:(NSDate *)anotherDate

Parameter :anotherDate Tanggal untuk membandingkan penerima. Nilai ini tidak boleh nol. Jika nilainya nol, perilaku tidak terdefinisi dan dapat berubah di versi Mac OS X mendatang.

Nilai Pengembalian:

  • Jika penerima dan tanggal lain sama persis satu sama lain, NSOrderedSame
  • Jika penerima lebih lambat dari tanggal yang lain, NSOrderedDescending
  • Jika penerima lebih awal daripada Tanggal yang lain NSOrderedAscending,.
Gary
sumber
@ Irene apakah ada cara untuk membandingkan dua objek NSDate di mana hanya komponen waktu yang berbeda? Untuk beberapa alasan metode di atas tidak berfungsi.
KAMU
12

Anda ingin menggunakan NSDate bandingkan :, laterDate :, beforeDate :, atau isEqualToDate: metode. Menggunakan operator <dan> dalam situasi ini membandingkan pointer, bukan tanggal

Dan F
sumber
11
- (NSDate *)earlierDate:(NSDate *)anotherDate

Ini mengembalikan yang lebih awal dari penerima dan Tanggal lain. Jika keduanya sama, penerima dikembalikan.

Maulik
sumber
1
Perhatikan bahwa objek dukungan NSDates dapat dioptimalkan pada versi 64-bit dari kode kompilasi Anda sehingga tanggal yang mewakili waktu yang sama akan memiliki alamat yang sama. Dengan demikian jika cDate = [aDate earlierDate:bDate]kemudian cDate == aDatedan cDate == bDatekeduanya bisa benar. Menemukan ini melakukan beberapa pekerjaan tanggal di iOS 8.
Ben Flynn
1
Sebaliknya, pada platform 32 bit, jika tanggalnya tidak sama, -earlierDate:(dan -laterDate:) tidak dapat mengembalikan penerima maupun argumen.
Ben Lings
7

Beberapa utilitas tanggal, termasuk perbandingan dalam BAHASA INGGRIS, yang bagus:

#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

Pelaksanaan:

#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
Dan Rosenstark
sumber
1
Atau cukup gunakan: github.com/erica/NSDate-Extensions
Dan Rosenstark
6

Kamu harus menggunakan :

- (NSComparisonResult)compare:(NSDate *)anotherDate

untuk membandingkan tanggal. Tidak ada operator kelebihan muatan di tujuan C.

Joris Mans
sumber
6

Mengapa kalian tidak menggunakan NSDatemetode perbandingan ini :

- (NSDate *)earlierDate:(NSDate *)anotherDate;
- (NSDate *)laterDate:(NSDate *)anotherDate;
justicepenny
sumber
4

Saya telah menghadapi situasi yang hampir sama, tetapi dalam kasus saya, saya memeriksa apakah jumlah hari berbeda

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.

Berguna saat Anda perlu membandingkan NSDate dalam satuan Hari / Bulan / Tahun

Andy
sumber
NSDayCalendarUnit sudah tidak digunakan lagi, jadi gunakan NSCalendarUnitDay sebagai gantinya
Mazen Kasser
2

Anda dapat membandingkan dua tanggal dengan metode ini juga

        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;

        }
kapil
sumber
0

Saya sudah mencobanya semoga berhasil untuk Anda

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];
Konsep Infoway
sumber
0

Gunakan fungsi sederhana ini untuk perbandingan tanggal

-(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;}
Akhtar
sumber