Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm developing an iPhone app that is heavily Calendar-based, and it requires a good amount of (what I'm calling) "date boundaries."

I use these "date boundaries" to fetch EKEvents from specific calendars and display data for specific years, months, and quarters.

SPECIAL NOTE: This app is for government employees, specifically military, so the first day of their fiscal year is Oct 1st. (convenient, huh?) I can't use the calendar object to get "events from a quarter" because the fiscal year is all out of whack, so I have to do everything manually, ergo the "date boundaries."

My Question: Can these NSDateComponents objects be initialized in a loop? I'm not having performance issues, but I would prefer to have way less code to edit.

I need more than just a few of these dates, and I'm currently manually initializing all of them using NSDateComponents in my singleton class -(id)init method, like this:

-(id) init;
{
    self = [super init];
    if (!self) return nil;

    NSCalendar *cal = [NSCalendar autoupdatingCurrentCalendar];

    NSDate *now = [NSDate date];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    [dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]];
    NSString *refDate = [dateFormatter stringFromDate:now];
    NSString *year = [refDate substringWithRange:NSMakeRange(0,4)];
    NSString *month = [refDate substringWithRange:NSMakeRange(5,2)];

    self.currentYear = [year integerValue];

    int currentMonth = [month integerValue];
    if (currentMonth <= 9) {
        self.currentYear = [year integerValue] -1;
    }

    //init date boundaries that are used in several data model methods
    // notice Q1 starts Oct, 1st       

    NSDateComponents *previousYearQ4EndComps = [[NSDateComponents alloc] init];
    [previousYearQ4EndComps setYear:self.currentYear - 1];
    [previousYearQ4EndComps setMonth:9];
    [previousYearQ4EndComps setDay:30];
    [previousYearQ4EndComps setHour:24];
    [previousYearQ4EndComps setMinute:59];
    [previousYearQ4EndComps setSecond:59];
    self.previousYearQ4Ends = [cal dateFromComponents:previousYearQ4EndComps];

    NSDateComponents *lastYearQ1StartComps = [[NSDateComponents alloc] init];
    [lastYearQ1StartComps setYear:self.currentYear - 1];
    [lastYearQ1StartComps setMonth:10];
    [lastYearQ1StartComps setDay:1];
    [lastYearQ1StartComps setHour:1];
    [lastYearQ1StartComps setMinute:0];
    [lastYearQ1StartComps setSecond:0];
    self.lastYearQ1Starts = [cal dateFromComponents:lastYearQ1StartComps];

    NSDateComponents *lastYearQ1EndComps = [[NSDateComponents alloc] init];
    [lastYearQ1EndComps setYear:self.currentYear - 1];
    [lastYearQ1EndComps setMonth:12];
    [lastYearQ1EndComps setDay:31];
    [lastYearQ1EndComps setHour:24];
    [lastYearQ1EndComps setMinute:59];
    [lastYearQ1EndComps setSecond:59];
    self.lastYearQ1Ends = [cal dateFromComponents:lastYearQ1EndComps];

    NSDateComponents *lastYearQ2StartComps = [[NSDateComponents alloc] init];
    [lastYearQ2StartComps setYear:self.currentYear];
    [lastYearQ2StartComps setMonth:1];
    [lastYearQ2StartComps setDay:1];
    [lastYearQ2StartComps setHour:1];
    [lastYearQ2StartComps setMinute:0];
    [lastYearQ2StartComps setSecond:0];
    self.lastYearQ2Starts = [cal dateFromComponents:lastYearQ2StartComps];

    NSDateComponents *lastYearQ2EndComps = [[NSDateComponents alloc] init];
    [lastYearQ2EndComps setYear:self.currentYear];
    [lastYearQ2EndComps setMonth:3];
    [lastYearQ2EndComps setDay:31];
    [lastYearQ2EndComps setHour:24];
    [lastYearQ2EndComps setMinute:59];
    [lastYearQ2EndComps setSecond:59];
    self.lastYearQ2Ends = [cal dateFromComponents:lastYearQ2EndComps];

    // more date boundaries...

    self.eventStore = [[EKEventStore alloc] init];
    self.aftpCalendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.eventStore];
    self.thisYearsAFTPEvents = [[NSMutableArray alloc] init];
    self.lastYearsAFTPEvents = [[NSMutableArray alloc] init];

    // init the rest of my arrays...

    return self;

}

And here is an example of how I'm using the NSDates I create from the NSDateComponents to retrieve events from the calendar, which works perfectly fine:

- (void)fetchAFTPEvents {

    NSDate *now = [NSDate date];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    [dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]];
    NSString *refDate = [dateFormatter stringFromDate:now];
    NSString *year = [refDate substringWithRange:NSMakeRange(0,4)];
    NSString *month = [refDate substringWithRange:NSMakeRange(5,2)];

    self.currentYear = [year integerValue];
    int currentMonth = [month integerValue];

    if (currentMonth <= 9) {
        self.currentYear = [year integerValue] -1;
    }

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.aftpCalendar = [self.eventStore calendarWithIdentifier:[defaults valueForKey:@"AFTPs"]];
    NSArray *calendarArray = [NSArray arrayWithObject:self.aftpCalendar];

    // Fetch Last Year Q1 Events 

    NSPredicate *lyQ1Predicate = [self.eventStore predicateForEventsWithStartDate:self.lastYearQ1Starts
                                                                      endDate:self.lastYearQ1Ends
                                                                    calendars:calendarArray];

    [self.lastYearsQ1AFTPEvents addObjectsFromArray:[self.eventStore eventsMatchingPredicate:lyQ1Predicate]];
    [self.lastYearsAFTPEvents addObject:self.lastYearsQ1AFTPEvents];

    // fetch the rest of the events...

    // call delegate
    [mainViewControllerDelegate updateLabels];
}

Thanks in advance for any help.

share|improve this question

1 Answer 1

up vote 1 down vote accepted

you could maintain one array with the starts of the quarters and one withe the ends. as only the months changes, you need just those.
Than you iterate over them and generate the dates

NSArray *startsOfQuarters = @[@10, @1, @4 , @7];
NSArray *endOfQuarters = @[@12, @3, @6 , @9];

NSMutableArray *startDates = [NSMutableArray array];

[startsOfQuarters enumerateObjectsUsingBlock:^(NSNumber *month, NSUInteger idx, BOOL *stop){
NSDateComponents *startComps = [[NSDateComponents alloc] init];
    [startComps setYear:self.currentYear - 1];
    [startComps setMonth:[month integerValue]];
    [startComps setDay:1];
    [startComps setHour:1];
    [startComps setMinute:0];
    [startComps setSecond:0];

    // create date from components
    [startDates addObject: date];
}];

do similar for ends.

Now the first quarter's boundries are defined by startDates[0] and endDates[0], se second by startDates[1] and endDates[1] and so on.


«Two or more, use a for»
— Edsger W. Dijkstra

share|improve this answer
    
Thanks! It'll take me a while to try this, so I'll report back to mark your answer if it works :) –  jhilgert00 Jan 12 '13 at 19:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.