Question

Scenario:

I have an expense tracking iOS Application and I am storing expenses from a expense detail view controller into a table view (with fetched results controller) that shows the list of expenses along with the category and amount and date. I do have a date attribute in my entity "Money" which is a parent entity for either an expense or an income.

Question:

What I want is to basically categorize my expenses on a monthly basis and display it as the section header title for example : (Nov 1 - Nov 30,2012) and it shows expenses amount and related stuff according to that particular month. Two buttons are provided in that view, if I would press the right button, it will increment the month by a month (Dec 1 - Dec 31, 2012) and similarly the left button would decrement the month by a month.

How would I accomplish that? I am trying the following code - which is kinda working. Suppose I have my current section header as (Nov1 - Nov 30, 2012) and when I press the left button, it gives me the section header (Oct 1 - Oct 30, 2012) which is wrong, it should be Oct 31, 2012 and not Oct 30, 2012.

- (NSDate *)firstDateOfTheMonth
{
    self.startDate = [NSDate date];

    NSCalendar* calendar = [NSCalendar currentCalendar];

    [calendar setTimeZone:[NSTimeZone localTimeZone]];

    NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:self.startDate];

    [components setDay:1];

    firstDateOfTheMonth = [[calendar dateFromComponents:components] retain];

    return firstDateOfTheMonth;

}

- (NSDate *)lastDateOfTheMonth
{
    NSCalendar* calendar = [NSCalendar currentCalendar];

    [calendar setTimeZone:[NSTimeZone localTimeZone]];

    NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:firstDateOfTheMonth];

    [components setMonth:[components month]+1];
    [components setDay:0];

    lastDateOfTheMonth = [[calendar dateFromComponents:components] retain];

    return lastDateOfTheMonth;
}

Then I have a method called "monthCalculation" in which I call the above two methods.

- (void)monthCalculation
{
    [self firstDateOfTheMonth];
    [self lastDateOfTheMonth];
}

Now the following code when I press the left button (to decrement the month by a month):

- (IBAction)showPreviousDates:(id)sender
{
    [self monthCalculation];

    NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
    [dateComponents setMonth:-1];

    NSDate *newDate1 = [[NSCalendar currentCalendar]
                        dateByAddingComponents:dateComponents
                        toDate:firstDateOfTheMonth options:0];

    NSDate *newDate2 = [[NSCalendar currentCalendar]
                        dateByAddingComponents:dateComponents
                        toDate:lastDateOfTheMonth options:0];

    self.startDate = newDate1;
    self.endDate = newDate2;

    NSLog(@" self start date in previous mode =%@", self.startDate);
    NSLog(@" self end date in previous mode =%@", self.endDate);
} 

The following code when I press the right button (to increment the month by a month):

- (IBAction)showNextDates:(id)sender
{
    [self monthCalculation];

    NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
    [dateComponents setMonth:1];

    NSDate *newDate1 = [[NSCalendar currentCalendar]
                        dateByAddingComponents:dateComponents
                        toDate:firstDateOfTheMonth options:0];

    NSDate *newDate2 = [[NSCalendar currentCalendar]
                        dateByAddingComponents:dateComponents
                        toDate:lastDateOfTheMonth options:0];

    self.startDate = newDate1;
    self.endDate = newDate2;

    NSLog(@" self start date in previous mode =%@", self.startDate);
    NSLog(@" self end date in previous mode =%@", self.endDate);
} 

Am I doing it right? or there is a better way to do achieve this? Any help will be appreciated.

Was it helpful?

Solution

Here are some methods that should do what you want:

First, in your viewDidLoad method add:

self.startDate = [NSDate date];
[self updateDateRange];

This gives you a starting point. Then, I added the following five methods (Note: previousMonthButtonPressed/nextMonthButtonPressed should be wired up to your buttons):

// Return the first day of the month for the month that 'date' falls in:
- (NSDate *)firstDayOfMonthForDate:(NSDate *)date
{
    NSCalendar *cal         = [NSCalendar currentCalendar];
    NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                     fromDate:date];
    comps.day               = 1;
    return [cal dateFromComponents:comps];
}

// Return the last day of the month for the month that 'date' falls in:
- (NSDate *)lastDayOfMonthForDate:(NSDate *)date
{
    NSCalendar *cal         = [NSCalendar currentCalendar];
    NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                     fromDate:date];
    comps.month             += 1;
    comps.day               = 0;
    return [cal dateFromComponents:comps];
}

// Move the start date back one month
- (IBAction)previousMonthButtonPressed:(id)sender {
    NSCalendar *cal         = [NSCalendar currentCalendar];
    NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                     fromDate:self.startDate];
    comps.month             -= 1;
    self.startDate          = [cal dateFromComponents:comps];
    [self updateDateRange];
}

// Move the start date forward one month
- (IBAction)nextMonthButtonPressed:(id)sender {
    NSCalendar *cal         = [NSCalendar currentCalendar];
    NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                     fromDate:self.startDate];
    comps.month             += 1;
    self.startDate          = [cal dateFromComponents:comps];
    [self updateDateRange];
}

// Print the new range of dates.
- (void)updateDateRange
{
    NSLog(@"First day of month: %@", [self firstDayOfMonthForDate:self.startDate]);
    NSLog(@"Last day of month: %@",  [self lastDayOfMonthForDate:self.startDate]);
}

OTHER TIPS

Try this:

- (NSDate *)lastDateOfTheMonth
{
    NSCalendar* calendar = [NSCalendar currentCalendar];
    [calendar setTimeZone:[NSTimeZone localTimeZone]];

    NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:firstDateOfTheMonth];
    [components setMonth:[components month]+1];

    NSDateComponents* offset = [[[NSDateComponents alloc] init] retain];
    [offset setDay:-1];

    lastDateOfTheMonth = [[calendar dateByAddingComponents:offset toDate:[components date] options:0] retain];
    return lastDateOfTheMonth;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top