2009-08-25 2 views
5

Ich erstelle einen Berichtgenerator in Cocoa, und ich muss bequeme Datumsbereiche wie "Heute", "Diese Woche", "Dieser Monat", "Dieses Jahr" etc.Wie kann ich auf der Grundlage eines bestimmten NSDate geeignete Datumsbereiche generieren?

Gibt es eine Gute Möglichkeit, das zu tun? Hier ist mein Skelett so weit:

@interface DateRange : NSObject 
{ 
    NSDate startDate; 
    NSDate endDate; 
} 

@property (nonatomic, retain) NSDate * startDate; 
@property (nonatomic, retain) NSDate * endDate; 

+ (DateRange *)rangeForDayContainingDate:(NSDate *)date; 
+ (DateRange *)rangeForWeekContainingDate:(NSDate *)date; 
+ (DateRange *)rangeForMonthContainingDate:(NSDate *)date; 
+ (DateRange *)rangeForYearContainingDate:(NSDate *)date; 

@end 

Einige Beispielanwendungsfälle wäre wie folgt:

DateRange * thisWeek = [DateRange rangeForWeekContainingDate:[NSDate date]]; 
DateRange * thisYear = [DateRange rangeForYearContainingDate:[NSDate date]]; 

Im Grunde möchte ich das zurück DateRange Objekt, um die Start- und Enddaten für die Woche enthalten, Monat oder Jahr um das Zieldatum herum. Zum Beispiel (in Pseudo-Code):

NSDate * today = [August 25, 2009]; 
DateRange * thisWeek = [DateRange rangeForWeekContainingDate:today]; 
assert(thisWeek.startDate == [August 23, 3009]); 
assert(thisWeek.endDate == [August 29, 3009]); 

Update:

konnte ich diese Arbeit dank der answer provided by Kendall Helmstetter Geln bekommen. Dies ist die komplette Methode für einen einwöchigen Bereich:

+ (DateRange *)rangeForWeekContainingDate:(NSDate *)date 
{ 
    DateRange * range = [[self alloc] init]; 

    // start of the week 
    NSDate * firstDay; 
    [[self calendar] rangeOfUnit:NSWeekCalendarUnit 
         startDate:&firstDay 
         interval:0 
         forDate:date]; 
    [range setStartDate:firstDay]; 

    // end of the week 
    NSDateComponents * oneWeek = [[NSDateComponents alloc] init]; 
    [oneWeek setWeek:1]; 
    [range setEndDate:[[self calendar] dateByAddingComponents:oneWeek 
                 toDate:firstDay 
                 options:0]]; 
    [oneWeek release]; 

    return [range autorelease]; 
} 
+2

Eine Sache, die Sie vielleicht in Ihrer Lösung ändern wollen, ist '[[self alloc zu haben ] init] 'anstelle von' [[DateRange alloc ...], so ordnen sich Unterklassen auch selbst zu, anstatt immer DateRange zu verwenden, was ihre Oberklasse sein könnte. – jbrennan

+1

@jbrennan: guter Punkt. Ich habe es geändert. –

Antwort

2

Nun, da TimeInterval in Sekunden, sind nur die Mathematik, um herauszufinden, wie viele Sekunden in einem Tag sind:

60 Sekunden * 60 Minuten * 24 Stunden = 1 Tag.

Dann können Sie in Ihrer rangeForDayContainingDate Methode Datenkomponenten extrahieren, den aktuellen Tag abrufen, ein neues Datum basierend auf dem Tag mit Stunden und Minuten auf 0:00 erstellen und das Enddatum erstellen, indem Sie das berechnete Zeitintervall hinzufügen über.

+0

+1 Das sieht vielversprechend aus. Datumskomponenten könnten genau das sein, wonach ich gesucht habe. –

+0

Danke, mein Herr! Deine Antwort wies mich in die richtige Richtung. Ich habe die vollständige Lösung für einen einwöchigen Bereich als Bearbeitung der ursprünglichen Frage gepostet. –

+0

Gern geschehen, bitte fühlen Sie sich frei, Ihre eigene Antwort als die tatsächliche Lösung anstelle meiner groben Richtungen zu markieren ... Ich werde nicht beleidigt sein. –

8

Aus Gründen der Vollständigkeit, hier meine endgültige Lösung ist (mit Dank an Kendall Helm Geln und jbrennan):

+ (NSCalendar *)calendar 
{ 
    NSCalendar * gregorian = [[NSCalendar alloc] 
           initWithCalendarIdentifier:NSGregorianCalendar]; 
    return [gregorian autorelease]; 
} 

//////////////////////////////////////////////////////////////// 

+ (NSDateComponents *)singleComponentOfUnit:(NSCalendarUnit)unit 
{ 
    NSDateComponents * component = [[NSDateComponents alloc] init]; 

    switch (unit) 
    { 
     case NSDayCalendarUnit: [component setDay:1]; break; 
     case NSWeekCalendarUnit: [component setWeek:1]; break; 
     case NSMonthCalendarUnit: [component setMonth:1]; break; 
     case NSYearCalendarUnit: [component setYear:1]; break; 
    } 

    return [component autorelease]; 
} 

//////////////////////////////////////////////////////////////// 

+ (WM_DateRange *)rangeForUnit:(NSCalendarUnit)unit 
       surroundingDate:(NSDate *)date 
{ 
    WM_DateRange * range = [[self alloc] init]; 

    // start of the period 
    NSDate * firstDay; 
    [[self calendar] rangeOfUnit:unit 
         startDate:&firstDay 
         interval:0 
         forDate:date]; 
    [range setStartDate:firstDay]; 

    // end of the period 
    [range setEndDate:[[self calendar] 
     dateByAddingComponents:[self singleComponentOfUnit:unit] 
         toDate:firstDay 
         options:0]]; 

    return [range autorelease]; 
} 

//////////////////////////////////////////////////////////////// 

+ (WM_DateRange *)rangeForDayContainingDate:(NSDate *)date 
{ return [self rangeForUnit:NSDayCalendarUnit surroundingDate:date]; } 

+ (WM_DateRange *)rangeForWeekContainingDate:(NSDate *)date 
{ return [self rangeForUnit:NSWeekCalendarUnit surroundingDate:date]; } 

+ (WM_DateRange *)rangeForMonthContainingDate:(NSDate *)date 
{ return [self rangeForUnit:NSMonthCalendarUnit surroundingDate:date]; } 

+ (WM_DateRange *)rangeForYearContainingDate:(NSDate *)date 
{ return [self rangeForUnit:NSYearCalendarUnit surroundingDate:date]; } 

//////////////////////////////////////////////////////////////// 

- (void)dealloc 
{ 
    [endDate release]; 
    [startDate release]; 
    [super dealloc]; 
} 
+0

Das hat mir bei einem Projekt, an dem ich gerade arbeite, sehr geholfen - danke für Ihre endgültige Antwort !! – Jim