2009-08-25 15 views
5

Estoy creando un generador de informes en Cocoa, y necesito para producir los intervalos de fechas convenientes tales como "Hoy", "Esta Semana", "Este mes", "este año", etc.¿Cómo puedo generar rangos de fechas convenientes basados ​​en un NSDate dado?

¿Hay una buena forma de hacer esto? Aquí está mi esqueleto hasta el momento:

@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 

Algunos casos ejemplo de uso sería de la siguiente manera:

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

Esencialmente, quiero que el devuelto DateRange objeto que contiene las fechas de inicio y fin de la semana, mes o año que rodea la fecha objetivo. Por ejemplo (en pseudocódigo):

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

actualización:

que era capaz de conseguir este trabajo gracias a la answer provided by Kendall Helmstetter Geln. Aquí está el método completo para un rango de una semana:

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

Una cosa es posible que desee cambiar en su solución es tener '[alloc auto [ ] init] 'en lugar de' [[DateRange alloc ... ', de esta forma las subclases también se asignarán, en lugar de usar siempre DateRange, que podría ser su superclase. – jbrennan

+1

@jbrennan: buen punto. Lo he cambiado –

Respuesta

2

Bueno ya timeInterval es en cuestión de segundos, simplemente hacer los cálculos para averiguar cuántos segundos son en un día:

60 segundos * 60 minutos * 24 horas = 1 día.

Luego, en su método rangeForDayContainingDate puede extraer los componentes de fecha, obtener el día actual, crear una nueva fecha basada en el día con horas y minutos configurados a 0:00 y crear la fecha de finalización agregando el intervalo de tiempo calculado encima.

+0

+1 Eso parece prometedor. Los componentes de fecha podrían ser exactamente lo que estaba buscando. –

+0

¡Gracias, señor! Tu respuesta me indicó la dirección correcta. He publicado la solución completa para un rango de una semana como una edición de la pregunta original. –

+0

De nada, siéntase libre de marcar su propia respuesta como la solución real en lugar de mis rudas instrucciones ... No me ofenderé. –

8

En aras de la exhaustividad, aquí está mi solución final (con gracias a Kendall Helmstetter Geln y 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

Esto me ayudó mucho en un proyecto en el que estoy trabajando, ¡gracias por publicar su respuesta final! – Jim

Cuestiones relacionadas