2つのNSDateを比較する方法:どちらが新しいですか?


244

私はdropBox同期を達成しようとしています。2つのファイルの日付を比較する必要があります。1つは私のdropBoxアカウントにあり、もう1つは私のiPhoneにあります。

次のことを思いつきましたが、思いがけない結果が出ました。2つの日付を比較するときに、根本的に何か間違っていると思います。私は単に> <演算子を使用しましたが、2つの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
@JoshCaswellそれが実際の複製である場合、なぜそれらをマージしないのですか?あなたはそれを以前にやったことがある...
Dan Rosenstark 2014年

1
ダイヤモンドのモデレーターだけが@Yarのマージを実行できます。
jscs 2014年

回答:


658

2つの日付を想定します。

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 earlyDate:date2]などをいじり回しているビート...ありがとう-なんらかの理由で、compare:以前は使用することを考えていなかった。
SomaMan 2012

11
NSOrderedAscending <0およびNSOrderedDescending> 0であるという事実に依存したいと思います。これにより、比較が読みやすくなります。指摘した。;-)
jpap 2013

まあ-比較メソッドは、1つずれたエラーと同じくらいエラーが発生しやすいです。したがって、両方の遅い日付を返す(NSDate *)lateDate:(NSDate *)anotherDateを使用する必要があります。予想される結果を比較するだけで完了です!「Waaaitの下降/上昇?!」をいじる必要はありません。
masi

@jpapそれも私を台無しにした。Appleはあなたに結果をdate1 -> date2昇順/降順であると考えるように求めているようです(したがって、date1はそれぞれ後または前です)。
ジャック

@Jackは、並べ替えアルゴリズムがマジックエレメント(-1,0,1)を使わない、より抽象的な方法であり、要素を並べ替えます。また、これらの定数をより読みやすい名前で自分で再定義することもできます。私の答えは仕事をすることですが、可読コードの受賞者ではありません。下にスクロールしてください。他にも良いものがあります。
Nick Weaver 14

50

パーティーには遅れますが、NSDateオブジェクトを比較する別の簡単な方法は、 '>' '<' '=='などを簡単に使用できるプリミティブ型に変換することです。

例えば。

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

timeIntervalSinceReferenceDate日付を基準日(2001年1月1日、GMT)からの秒数に変換します。timeIntervalSinceReferenceDateNSTimeInterval(double typedef)を返すので、プリミティブコンパレーターを使用できます。


4
(NSComparisonResult)compare:(NSDate *)この単純な操作よりも少し直感的ですが、それでもかなり冗長です...(いつものように)
Pierre de LESPINAY 14

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 2015年

@JohnVanDijk拡張機能の中に置くことはできません。私は拡張子と同じファイルに入れますが、外部のだろう{ ... }
アンドリュー

13

NSDate 比較機能があります。

compare:NSComparisonResult受信者と指定された別の日付の時間的順序を示す値を返します。

(NSComparisonResult)compare:(NSDate *)anotherDate

パラメータanotherDate レシーバーと比較する日付。この値はnilであってはなりません。値がnilの場合、動作は定義されておらず、Mac OS Xの将来のバージョンで変更される可能性があります。

戻り値:

  • レシーバとanotherDateが完全に等しい場合、 NSOrderedSame
  • 受信者がanotherDateより遅れている場合、 NSOrderedDescending
  • 受信機はanotherDateよりも時間的に前である場合には、NSOrderedAscending

@Ireneは、時間コンポーネントのみが異なる2つのNSDateオブジェクトを比較する方法はありますか?何らかの理由で、上記の方法は機能しません。
2012年

12

NSDateのcompare:、laterDate:、earlyDate :、またはisEqualToDate:メソッドを使用したい。この状況で<および>演算子を使用すると、日付ではなくポインタが比較されます


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

これは、レシーバとanotherDateの早い方を返します。両方が同じ場合、レシーバーが返されます。


1
NSDatesのバッキングオブジェクトは、コンパイルされたコードの64ビットバージョンで最適化され、同じ時間を表す日付が同じアドレスを持つようになる場合があります。したがって、もしそうならcDate = [aDate earlierDate:bDate]cDate == aDateそしてcDate == bDate両方とも真であることができます。これはiOS 8でいくつかの日付作業を行っていることがわかりました
ベンフリン2015

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を使用してください
Mazen Kasser

2

この方法でも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.