2009-08-25 5 views
5

Tworzę generator raportów w kakao i muszę tworzyć dogodne zakresy dat, takie jak "Dzisiaj", "W tym tygodniu", "W tym miesiącu", "W tym roku", itp.Jak wygenerować dogodne zakresy dat na podstawie danego NSDate?

Czy istnieje dobry sposób na zrobienie tego? Oto mój szkielet dotąd:

@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 

Niektóre przypadki przykład stosowanie byłoby następująco:

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

Zasadniczo, chcę zwrócony DateRange obiekt do zawierać daty rozpoczęcia i zakończenia na tydzień, miesiąc lub rok wokół docelowej daty. Na przykład (w Pseudokod):

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

zmiana:

udało mi się uzyskać tej pracy dzięki answer provided by Kendall Helmstetter Geln. Oto pełna metoda przedziale tygodniowym:

+ (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

Jedno może chcesz zmienić w swoim rozwiązaniem jest mieć '[[self alloc ] init] 'zamiast' [[DateRange alloc ... ', w ten sposób podklasy również będą się alokować, zamiast zawsze używać DateRange, która może być ich nadklasą. – jbrennan

+1

@jbrennan: dobry punkt. Zmieniłem to. –

Odpowiedz

2

Dobrze od TimeInterval jest w sekundach, po prostu do matematyki, aby dowiedzieć się, ile sekund są w dzień:

60 sekund * 60 minut * 24 godziny = 1 dzień.

Następnie w metodzie rangeForDayContainingDate można wyodrębnić składniki daty, pobrać bieżący dzień, utworzyć nową datę na podstawie dnia z godzinami i minutami ustawionymi na 0:00, a także utworzyć datę końcową dodając przedział czasu obliczony powyżej.

+0

+1 To wygląda obiecująco. Składniki daty mogą być dokładnie tym, czego szukałem. –

+0

Dziękuję, proszę pana! Twoja odpowiedź wskazała mi właściwy kierunek. Opublikowalem pełne rozwiazanie dla zakresu jednotygodniowego jako edycję oryginalnego pytania. –

+0

Nie ma za co, proszę o zaznaczenie własnej odpowiedzi jako rzeczywistego rozwiązania zamiast moich przybliżonych wskazówek ... Nie obrażę się. –

8

Dla kompletności, tutaj jest moje ostateczne rozwiązanie (z podziękowaniem Kendall Helmstetter Geln i 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

Pomogło mi to znacznie w projekcie, nad którym pracuję - dziękuję za wysłanie ostatecznej odpowiedzi !! – Jim