wake-up-neo.net

Anzahl der Tage zwischen zwei NSDates

Wie kann ich die Anzahl der Tage zwischen zwei NSDate-Werten bestimmen (unter Berücksichtigung der Zeit)?

Die NSDate-Werte sind in beliebiger Form [NSDate date].

Wenn ein Benutzer in meiner iPhone-App den inaktiven Status angibt, speichere ich insbesondere den folgenden Wert:

exitDate = [NSDate date];

Und wenn sie die App wieder öffnen, bekomme ich die aktuelle Uhrzeit:

NSDate *now = [NSDate date];

Nun möchte ich folgendes implementieren:

-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now
148
CodeGuy

Hier ist eine Implementierung, mit der ich die Anzahl der Kalendertage zwischen zwei Datumsangaben ermittelt habe:

+ (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
    NSDate *fromDate;
    NSDate *toDate;

    NSCalendar *calendar = [NSCalendar currentCalendar];

    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
        interval:NULL forDate:fromDateTime];
    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
        interval:NULL forDate:toDateTime];

    NSDateComponents *difference = [calendar components:NSCalendarUnitDay
        fromDate:fromDate toDate:toDate options:0];

    return [difference day];
}

BEARBEITEN:

Fantastische Lösung oben, hier ist die Swift-Version unten als Erweiterung für NSDate:

extension NSDate {
  func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
    let calendar = NSCalendar.currentCalendar()
    if let timeZone = timeZone {
      calendar.timeZone = timeZone
    }

    var fromDate: NSDate?, toDate: NSDate?

    calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
    calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)

    let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
    return difference.day
  }
}

Je nach Anwendungsfall wird ein gewisser Kraftaufwand beim Entpacken ausgeführt, den Sie entfernen möchten.

Die obige Lösung funktioniert auch für andere Zeitzonen als die aktuelle Zeitzone, perfekt für eine App, die Informationen zu Orten auf der ganzen Welt anzeigt.

402
Brian

Hier ist die beste Lösung, die ich gefunden habe. Scheint die von Apple genehmigte Methode zur Bestimmung einer beliebigen Anzahl von Einheiten zwischen NSDates zu verwenden.

- (int)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
    NSUInteger unitFlags = NSDayCalendarUnit;
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 
    NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
    return [components day]+1;
}

Z.B. Wenn Sie auch Monate wünschen, können Sie 'NSMonthCalendarUnit' als unitFlag angeben.

Um den ursprünglichen Blogger zu würdigen, habe ich diese Informationen hier gefunden (obwohl es einen kleinen Fehler gab, den ich oben behoben habe): http://cocoamatic.blogspot.com/2010/09/nsdate-number-of -days-between-two-dates.html? showComment = 1306198273659 # c6501446329564880344

117
Biosopher

Swift 3.0 Update

extension Date {

    func differenceInDaysWithDate(date: Date) -> Int {
        let calendar = Calendar.current

        let date1 = calendar.startOfDay(for: self)
        let date2 = calendar.startOfDay(for: date)

        let components = calendar.dateComponents([.day], from: date1, to: date2)
        return components.day ?? 0
    }
}

Swift 2.0 Update

extension NSDate {

    func differenceInDaysWithDate(date: NSDate) -> Int {
        let calendar: NSCalendar = NSCalendar.currentCalendar()

        let date1 = calendar.startOfDayForDate(self)
        let date2 = calendar.startOfDayForDate(date)

        let components = calendar.components(.Day, fromDate: date1, toDate: date2, options: [])
        return components.day
    }

}

Originallösung

Eine andere Lösung in Swift.

Wenn Sie die genaue Tageszahl zwischen zwei Datumsangaben ermitteln möchten, können Sie dieses Problem folgendermaßen umgehen: 

// Assuming that firstDate and secondDate are defined
// ...

var calendar: NSCalendar = NSCalendar.currentCalendar()

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)

let flags = NSCalendarUnit.DayCalendarUnit
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)

components.day  // This will return the number of day(s) between dates
23

Ich verwende diese als Kategoriemethode für die NSDate-Klasse

// returns number of days (absolute value) from another date (as number of midnights beween these dates)
- (int)daysFromDate:(NSDate *)pDate {
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSInteger startDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
                                           inUnit:NSCalendarUnitEra
                                          forDate:[NSDate date]];
    NSInteger endDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
                                         inUnit:NSCalendarUnitEra
                                        forDate:pDate];
    return abs(endDay-startDay);
}
13
jki

Ich brauchte die Anzahl der Tage zwischen zwei Terminen einschließlich des Anfangstages. z.B. Tage zwischen dem 14-2-2012 und 16-2-2012 würden ein Ergebnis von 3 ergeben.

+ (NSInteger)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
        NSUInteger unitFlags = NSDayCalendarUnit;
        NSCalendar* calendar = [NSCalendar currentCalendar];
        NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
        NSInteger daysBetween = abs([components day]);
    return daysBetween+1;
}

Beachten Sie, dass es egal ist, in welcher Reihenfolge Sie die Daten angeben. Es wird immer eine positive Zahl zurückgegeben.

8
orkoden
NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;

dateDiff ist dann die Anzahl der Sekunden zwischen den beiden Datumsangaben. Teilen Sie einfach die Anzahl der Sekunden pro Tag. 

7
chris

@Brian

Brians Antwort ist zwar gut, er berechnet nur die Differenz in Tagen in 24-Stunden-Schritten, jedoch nicht die Kalendertagdifferenzen. Zum Beispiel ist 23:59 am 24. Dezember nur eine Minute vom Weihnachtstag entfernt, für viele Anwendungen, die als ein Tag betrachtet werden. Brians DaysBetween-Funktion würde 0 zurückgeben.

Ich leihe mir Brians ursprüngliche Implementierung und den Beginn/das Ende des Tages aus und verwende in meinem Programm Folgendes: ( NSDate Anfang und Ende des Tages )

- (NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];
    return [cal dateFromComponents:components];
}

- (NSDate *)endOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
    [components setHour:23];
    [components setMinute:59];
    [components setSecond:59];
    return [cal dateFromComponents:components];
}

- (int)daysBetween:(NSDate *)date1 and:(NSDate *)date2 {
    NSDate *beginningOfDate1 = [self beginningOfDay:date1];
    NSDate *endOfDate1 = [self endOfDay:date1];
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *beginningDayDiff = [calendar components:NSDayCalendarUnit fromDate:beginningOfDate1 toDate:date2 options:0];
    NSDateComponents *endDayDiff = [calendar components:NSDayCalendarUnit fromDate:endOfDate1 toDate:date2 options:0];
    if (beginningDayDiff.day > 0)
        return beginningDayDiff.day;
    else if (endDayDiff.day < 0)
        return endDayDiff.day;
    else {
        return 0;
    }
}
5
tooniz

Hier ist eine Implementierung von Brians Funktion in Swift:

class func daysBetweenThisDate(fromDateTime:NSDate, andThisDate toDateTime:NSDate)->Int?{

    var fromDate:NSDate? = nil
    var toDate:NSDate? = nil

    let calendar = NSCalendar.currentCalendar()

    calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &fromDate, interval: nil, forDate: fromDateTime)

    calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &toDate, interval: nil, forDate: toDateTime)

    if let from = fromDate {

        if let to = toDate {

            let difference = calendar.components(NSCalendarUnit.DayCalendarUnit, fromDate: from, toDate: to, options: NSCalendarOptions.allZeros)

            return difference.day
        }
    }

    return nil
}
3
PJeremyMalouf

Fügen Sie einfach eine Antwort für diejenigen hinzu, die diese Seite in Swift besuchen. Die Vorgehensweise ist ziemlich gleich. 

private class func getDaysBetweenDates(startDate:NSDate, endDate:NSDate) -> NSInteger {

    var gregorian: NSCalendar = NSCalendar.currentCalendar();
    let flags = NSCalendarUnit.DayCalendarUnit
    let components = gregorian.components(flags, fromDate: startDate, toDate: endDate, options: nil)

    return components.day
}

Diese Antwort wurde hier im Diskussionsteil der folgenden Methode gefunden: 

components(_:fromDate:toDate:options:)
3
Mihir

Ein anderer Ansatz:

NSDateFormatter* dayFmt = [[NSDateFormatter alloc] init];
[dayFmt setTimeZone:<whatever time zone you want>];
[dayFmt setDateFormat:@"g"];
NSInteger firstDay = [[dayFmt stringFromDate:firstDate] integerValue];    
NSInteger secondDay = [[dayFmt stringFromDate:secondDate] integerValue];
NSInteger difference = secondDay - firstDay;

Hat gegenüber dem timeIntervalSince...-Schema den Vorteil, dass die Zeitzone berücksichtigt werden kann, und es gibt keine Mehrdeutigkeit bei Intervallen von wenigen Sekunden oder einem Tag.

Und ein bisschen kompakter und weniger verwirrend als die NSDateComponents-Ansätze.

3
Hot Licks

Habe einen, nicht sicher, dass es genau das ist, was Sie wollen, aber es könnte einigen von Ihnen helfen, (hat mir geholfen !!)

Mein Ziel war es zu wissen, ob ich zwischen zwei Tagen (weniger als 24 Stunden Unterschied) einen "Overday" -Tag + 1 hatte:

ich habe folgendes getan (ein bisschen archaisch, gebe ich zu)

NSDate *startDate = ...
NSDate *endDate = ...

NSDate wurde bereits von einem anderen NSDateFormatter formatiert (dies ist nur für diesen Zweck :)

NSDateFormatter *dayFormater = [[NSDateFormatter alloc]init];
[dayFormater setDateFormat:@"dd"];

int startDateDay = [[dayFormater stringFromDate:startDate]intValue];

int endDateDay = [[dayFormater stringFromDate:dateOn]intValue];

if (endDateDay > startDateDay) {
    NSLog(@"day+1");
} else {
    NSLog(@"same day");
}

vielleicht existiert so etwas schon, aber es wurde nicht gefunden

Tim

1
Tim

Meinen Sie Kalendertage oder 24-Stunden-Zeiträume? d. h. ist Dienstag um 9 Uhr ein Tag vor Mittwoch um 6 Uhr oder weniger als ein Tag?

Wenn Sie das erstere meinen, ist es etwas kompliziert und Sie müssen über NSCalendar und NSDateComponent auf Manipulationen zurückgreifen, an die ich mich nicht aus dem Kopf erinnere.

Wenn Sie Letzteres meinen, beziehen Sie sich einfach auf die Zeitintervalle der Datumsangaben seit dem Referenzdatum, subtrahieren Sie sie voneinander und teilen Sie sie durch 24 Stunden (24 * 60 * 60), um das ungefähre Intervall zu erhalten.

1

Die Lösung, die ich fand, war:

+(NSInteger)getDaysDifferenceBetween:(NSDate *)dateA and:(NSDate *)dateB {

  if ([dateA isEqualToDate:dateB]) 
    return 0;

  NSCalendar * gregorian = 
        [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];



  NSDate * dateToRound = [dateA earlierDate:dateB];
  int flags = (NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit);
  NSDateComponents * dateComponents = 
         [gregorian components:flags fromDate:dateToRound];


  NSDate * roundedDate = [gregorian dateFromComponents:dateComponents];

  NSDate * otherDate = (dateToRound == dateA) ? dateB : dateA ;

  NSInteger diff = abs([roundedDate timeIntervalSinceDate:otherDate]);

  NSInteger daysDifference = floor(diff/(24 * 60 * 60));

  return daysDifference;
}

Hier runde ich effektiv das erste Datum auf, um am Anfang des Tages zu beginnen und dann die Differenz zu berechnen, wie Jonathan es oben vorgeschlagen hat ...

0

Ich habe eine Open-Source-Klasse Bibliothek veröffentlicht, um genau dies zu tun.

Werfen Sie einen Blick auf/- RelativeDateDescriptor , um die Zeitdifferenz wie folgt zu erhalten:.

RelativeDateDescriptor *descriptor = [[RelativeDateDescriptor alloc] initWithPriorDateDescriptionFormat:@"%@ ago" postDateDescriptionFormat:@"in %@"];

// date1: 1st January 2000, 00:00:00
// date2: 6th January 2000, 00:00:00
[descriptor describeDate:date2 relativeTo:date1]; // Returns '5 days ago'
[descriptor describeDate:date1 relativeTo:date2]; // Returns 'in 5 days'
0
mmccomb

Warum nicht einfach:

int days = [date1 timeIntervalSinceDate:date2]/24/60/60;
0
MyCSharpCorner