Frage

Was ist die effizienteste/empfohlene Art, zwei NSDates zu vergleichen?Ich würde gerne sehen können, ob beide Daten unabhängig von der Uhrzeit am selben Tag liegen, und habe begonnen, Code zu schreiben, der timeIntervalSinceDate verwendet:Methode innerhalb der NSDate-Klasse und ruft die Ganzzahl dieses Werts dividiert durch die Anzahl der Sekunden an einem Tag ab.Das scheint langatmig zu sein und ich habe das Gefühl, dass mir etwas Offensichtliches entgeht.

Der Code, den ich zu reparieren versuche, ist:

if (!([key compare:todaysDate] == NSOrderedDescending))
{
    todaysDateSection = [eventSectionsArray count] - 1;
}

Dabei sind key und todaysDate NSDate-Objekte und todaysDate wird erstellt mit:

NSDate *todaysDate = [[NSDate alloc] init];

Grüße

Dave

War es hilfreich?

Lösung

Sie setzen die Uhrzeit im Datum auf 00:00:00, bevor Sie den Vergleich durchführen:

unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar* calendar = [NSCalendar currentCalendar];

NSDateComponents* components = [calendar components:flags fromDate:date];

NSDate* dateOnly = [calendar dateFromComponents:components];

// ... necessary cleanup

Dann können Sie die Datumswerte vergleichen. Siehe das Übersicht in Referenzdokumentation.

Andere Tipps

Ich bin überrascht, dass keine anderen Antworten diese Option haben, um das Datum "Beginn des Tages" für die Objekte zu erhalten:

[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date1 interval:NULL forDate:date1];
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date2 interval:NULL forDate:date2];

Das setzt date1 und date2 zu Beginn ihrer jeweiligen Tage. Wenn sie gleich sind, sind sie am selben Tag.

Oder diese Option:

NSUInteger day1 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSDayCalendarUnit inUnit: forDate:date1];
NSUInteger day2 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date2];

Das setzt day1 und day2 zu etwas willkürlichen Werten, die verglichen werden können. Wenn sie gleich sind, sind sie am selben Tag.

Es gibt eine neue Methode, die mit iOS 8 in NSCalendar eingeführt wurde, die dies viel einfacher macht.

- (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit NS_AVAILABLE(10_9, 8_0);

Sie setzen die Granularität auf die wichtigsten Einheiten. Dies ignoriert alle anderen Einheiten und begrenzt den Vergleich mit den ausgewählten.

Für iOS8 und später überprüft, ob zwei Daten am selben Tag auftreten, ist so einfach:

[[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2]

Sehen Dokumentation

Dies ist eine Abkürzung aller Antworten:

NSInteger interval = [[[NSCalendar currentCalendar] components: NSDayCalendarUnit
                                                                  fromDate: date1
                                                                    toDate: date2
                                                                   options: 0] day];
    if(interval<0){
       //date1<date2
    }else if (interval>0){
       //date2<date1
    }else{
       //date1=date2
    }

Ich habe den Duncan C -Ansatz verwendet, ich habe einige Fehler behoben, die er gemacht hat

-(NSInteger) daysBetweenDate:(NSDate *)firstDate andDate:(NSDate *)secondDate { 

    NSCalendar *currentCalendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [currentCalendar components: NSDayCalendarUnit fromDate: firstDate toDate: secondDate options: 0];

    NSInteger days = [components day];

    return days;
}

Ich verwende diese kleine Util -Methode:

-(NSDate*)normalizedDateWithDate:(NSDate*)date
{
   NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
                                              fromDate: date];
   return [calendar_ dateFromComponents:components]; // NB calendar_ must be initialized
}

(Sie müssen offensichtlich einen Ivar anrufen lassen calendar_ enthält an NSCalendar.)

Mit dieser Weise ist es einfach zu überprüfen, ob ein Datum heute so ist:

[[self normalizeDate:aDate] isEqualToDate:[self normalizeDate:[NSDate date]]];

([NSDate date] Gibt das aktuelle Datum und die aktuelle Uhrzeit zurück.)

Dies ist natürlich sehr ähnlich zu dem, was Gregory vorschlägt. Der Nachteil dieses Ansatzes ist, dass er tendenziell viel vorübergehend erzeugt NSDate Objekte. Wenn Sie viele Daten bearbeiten, empfehle ich, eine andere Methode anzuwenden, z. B. den direkten Vergleich der Komponenten oder mit der Arbeit mit NSDateComponents Objekte statt von NSDates.

Die Antwort ist einfacher, als jeder es macht, es zu sein. NSCalendar hat eine Methode

components:fromDate:toDate:options

Mit dieser Methode können Sie den Unterschied zwischen zwei Daten mit den gewünschten Einheiten berechnen.

Schreiben Sie also eine Methode wie diese:

-(NSInteger) daysBetweenDate: (NSDate *firstDate) andDate: (NSDate *secondDate)
{
  NSCalendar *currentCalendar = [NSCalendar currentCalendar];
  NSDateComponents components* = [currentCalendar components: NSDayCalendarUnit
    fromDate: firstDate 
    toDate: secondDate
    options: 0];

  NSInteger days = [components days];
  return days;
}

Wenn die obige Methode Null zurückgibt, sind die beiden Daten am selben Tag.

Ab iOS 8.0 können Sie verwenden:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSComparisonResult dateComparison = [calendar compareDate:[NSDate date] toDate:otherNSDate toUnitGranularity:NSCalendarUnitDay];

Wenn das Ergebnis z. B. nsorderedDescending ist, ist ein anderes Date vor dem Datum der Tage vor dem Datum.

Ich sehe diese Methode in der NSCalendar -Dokumentation nicht, aber sie ist in der iOS 7.1 bis iOS 8.0 API -Unterschiede

Für Entwickler codieren in Swift 3

if(NSCalendar.current.isDate(selectedDate, inSameDayAs: NSDate() as Date)){
     // Do something
}

Mit Swift 3 können Sie je nach Bedarf eines der beiden folgenden Muster auswählen, um Ihr Problem zu lösen.


#1.Benutzen compare(_:to:toGranularity:) Methode

Calendar hat eine Methode namens compare(_:​to:​to​Granularity:​). compare(_:​to:​to​Granularity:​) hat die folgende Erklärung:

func compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResult

Vergleicht die angegebenen Daten mit der angegebenen Komponente und meldet sie ordered​Same wenn sie in der angegebenen Komponente und allen größeren Komponenten gleich sind, andernfalls auch nicht ordered​Ascending oder ordered​Descending.

Der folgende Playground-Code zeigt, wie man ihn gut verwenden kann:

import Foundation

let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"

/* Compare date1 and date2 */
do {
    let comparisonResult = calendar.compare(date1, to: date2, toGranularity: .day)
    switch comparisonResult {
    case ComparisonResult.orderedSame:
        print("Same day")
    default:
        print("Not the same day")
    }
    // Prints: "Not the same day"
}

/* Compare date1 and date3 */
do {
    let comparisonResult = calendar.compare(date1, to: date3, toGranularity: .day)
    if case ComparisonResult.orderedSame = comparisonResult {
        print("Same day")
    } else {
        print("Not the same day")
    }
    // Prints: "Same day"
}

#2.Benutzen dateComponents(_:from:to:)

Calendar hat eine Methode namens dateComponents(_:from:to:). dateComponents(_:from:to:) hat die folgende Erklärung:

func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents

Gibt die Differenz zwischen zwei Datumsangaben zurück.

Der folgende Playground-Code zeigt, wie man ihn gut verwenden kann:

import Foundation

let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"

/* Compare date1 and date2 */
do {
    let dateComponents = calendar.dateComponents([.day], from: date1, to: date2)
    switch dateComponents.day {
    case let value? where value < 0:
        print("date2 is before date1")
    case let value? where value > 0:
        print("date2 is after date1")
    case let value? where value == 0:
        print("date2 equals date1")
    default:
        print("Could not compare dates")
    }
    // Prints: date2 is before date1
}

/* Compare date1 and date3 */
do {
    let dateComponents = calendar.dateComponents([.day], from: date1, to: date3)
    switch dateComponents.day {
    case let value? where value < 0:
        print("date2 is before date1")
    case let value? where value > 0:
        print("date2 is after date1")
    case let value? where value == 0:
        print("date2 equals date1")
    default:
        print("Could not compare dates")
    }
    // Prints: date2 equals date1
}
int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24);
if (interval!=0){
   //not the same day;
}

Meine Lösung waren zwei Konvertierungen mit NSDateFormatter:

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyyMMdd"];
    [dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];

    NSDate *today = [NSDate dateWithTimeIntervalSinceNow:0];
    NSString *todayString=[dateFormat stringFromDate:today];
    NSDate *todayWithoutHour=[dateFormat dateFromString:todayString];

    if ([today compare:exprDate] == NSOrderedDescending)
    {
       //do  
    }

Die Dokumentation zu Nsdate zeigt an, dass die compare: und isEqual: Methoden werden sowohl einen grundlegenden Vergleich durchführen als auch die Ergebnisse bestellen, obwohl sie immer noch die Zeit berücksichtigen.

Wahrscheinlich ist der einfachste Weg, um die Aufgabe zu verwalten isToday Methode zur Wirkung der folgenden:

- (bool)isToday:(NSDate *)otherDate
{
    currentTime = [however current time is retrieved]; // Pardon the bit of pseudo-code

    if (currentTime < [otherDate timeIntervalSinceNow])
    {
        return YES;
    }
    else
    {
        return NO;
    }
}

Dies ist eine besonders hässliche Katze für die Haut, aber hier ist eine andere Möglichkeit, dies zu tun. Ich sage nicht, dass es elegant ist, aber es ist wahrscheinlich so nah wie möglich mit dem Datum/der Uhrzeit in iOS.

bool isToday = [[NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle] isEqualToString:[NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle]];
NSUInteger unit = NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit;
NSDateComponents *comp = [cal components:unit
                                fromDate:nowDate
                                  toDate:setDate
                                 options:0];

NSString *dMonth;
dMonth = [NSString stringWithFormat:@"%02ld",comp.month];
NSString *dDay;
dDay = [NSString stringWithFormat:@"%02ld",comp.day + (comp.hour > 0 ? 1 : 0)];

Vergleichen Sie auch die Stunde, um einen Unterschied von 1 Tag zu beheben

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top