Pergunta

I'm trying to do something that, for me, is a bit difficult. But I'm sure someone has some insight.

Given a date, say January 17, 2011, I'm trying to figure out the day that corresponds to this date one year ago. So January 17, 2011 is a Monday, and one year ago, this day fell on January 18, 2010 (a Monday as well). It turns out that January 18, 2010 is 354 days before January 17, 2011. I originally thought to just simply subtract 365 days for a non-leap year and 366 days for a leap year, but if you do that in this case, you would get January 17, 2010, which is a Sunday, not a Monday.

So, in Objective-C with NSDate and NSCalendar, how could I implement a function such as:

-(NSDate *)logicalOneYearAgo:(NSDate *)from {
}

In other words, the nth "weekday" of the nth month (where "weekday" is Monday or Tuesday or Wednesday etc)

Foi útil?

Solução 5

The answer turned out to be pretty simple. It turned out from trial and error. Here's the answer.

if the year is a leap year, subtract 365 days.

if the year is not a leap year, subtract 364 days.

Outras dicas

You use NSDateComponents like so:

- (NSDate *)logicalOneYearAgo:(NSDate *)from {

    NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

    NSDateComponents *offsetComponents = [[[NSDateComponents alloc] init] autorelease];
    [offsetComponents setYear:-1];

    return [gregorian dateByAddingComponents:offsetComponents toDate:from options:0];

}

This is covered in the Date and Time Programming Guide section on Calendrical Calculations, Adding Components to a Date

Specifically, the method of interest is dateByAddingComponents:toDate:options.

Using the Apple example as a basis, to subtract one year from the current date, you would do the following:

NSDate *today = [[NSDate alloc] init];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

/*
  Create a date components to represent the number of years to add to the current date.
  In this case, we add -1 to subtract one year.     
*/

NSDateComponents *addComponents = [[NSDateComponents alloc] init];
addComponents.year = - 1;

return [calendar dateByAddingComponents:addComponents toDate:today options:0];

I can't guarantee this is the most efficient way, but you could do it using NSCalendar and NSDateComponents. Pass your NSDate instance into [yourCalendar components:yourComponents fromDate:yourDate], subtract a year from the components, and then use [yourCalendar dateFromComponents:yourComp].

Sorry for not providing full code, but it's been a while since I've worked with those methods, and I don't want to give you code that won't work.

Substract 1 year. Then substract 1 day until you end up the same day of week you want.

Each year the "days of week" goes back 1 day, except when there is a feb 29th in between, they go back 2 days.

It's because a year is 52 weeks + 1 day (+2 for leap years).

So if you apply this logic indefinitely, you will end up, years after years, having a june 16th at may 24th.

If you don't want that to happen, you have to somewhere memorize the reference year and base your arithmetic on it.

For example, if the "new" monday is 4 days back (because 3 years have passed), you might prefer to chose the monday 3 days ahead in time, so as not to indefinitely substract days, years after years.

Hope it helps.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top