Domanda

I am making an iPhone count down app and need to know how many times a weekend (like Saturday and Sundays ) will happen until the date the user sets.

An example is how could I find how many weekends will occur from now (Monday, August 6th) until next week? I know the answer is 1 weekend, but I need to be able to figure this out using code.

The closest I have gotten is using the NSDateComponents and NSCalender and doing something close to the following.

NSDateComponents *weekendsLeftComponents = [calendar components:NSWeekCalendarUnit
                                                    fromDate:targetDate
                                                      toDate:[NSDate date]
                                                     options:0];

But from there I have hit the dreaded coders wall of no passing.

My problem is not exactly knowing how to go about doing this. It sounds like an Array could work, but I am afraid the Array could get rather large as some of these "things" could go as long as a couple years. (I am making an app that finds out how many days, weekends, etc until a person graduates.) Also my audience is mainly kids to teens with iPods, older ones too. I don't know how full their memory (ram) can get before running out.

Thank you so much in advance,

Alex Kafer

È stato utile?

Soluzione

It looks like your fromDate and toDate are backwards, assuming targetDate is in the future.

Here's how I'd solve this problem.

Create a category on NSCalendar to count the number of times a specific weekday occurs between two dates:

@interface NSCalendar (AlexCategory)

// The number of times weekday number `weekday` (1 = Sunday, 7 = Saturday)
// occurs between `fromDate` and `toDate`.  If `fromDate` falls on the desired
// weekday, it is counted.  If `toDate` falls on the desired weekday, it is NOT counted.
- (NSInteger)countOfWeekday:(NSInteger)weekday fromDate:(NSDate *)fromDate toDate:(NSDate *)toDate;

@end

To implement this new method, we'll start by getting the year, month, day, and weekday of the fromDate:

@implementation NSCalendar (AlexCategory)

- (NSInteger)countOfWeekday:(NSInteger)weekday fromDate:(NSDate *)fromDate toDate:(NSDate *)toDate {
    NSDateComponents *components = [self components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSWeekdayCalendarUnit fromDate:fromDate];

Next, we count how many days from fromDate to the next desired weekday:

    NSInteger daysUntilDesiredWeekday = weekday - components.weekday;
    // If fromDate is a Wednesday and weekday is Monday (for example),
    // daysUntilDesiredWeekday is negative.  Fix that.
    NSRange weekdayRange = [self minimumRangeOfUnit:NSWeekdayCalendarUnit];
    if (daysUntilDesiredWeekday < weekdayRange.location) {
        daysUntilDesiredWeekday += weekdayRange.length;
    }

Note that daysUntilDesiredWeekday will be zero if fromDate falls on the desired weekday.

Now we can create an NSDateComponents representing the first desired weekday on or after fromDate:

    NSDateComponents *firstDesiredWeekday = [[NSDateComponents alloc] init];
    firstDesiredWeekday.year = components.year;
    firstDesiredWeekday.month = components.month;
    firstDesiredWeekday.day = components.day + daysUntilDesiredWeekday;

We update fromDate to be that first desired weekday, and return 0 if it's on or after toDate:

    fromDate = [self dateFromComponents:firstDesiredWeekday];
    if ([fromDate compare:toDate] != NSOrderedAscending) {
        return 0;
    }

Next we count all the days (not just desired weekdays) from the updated fromDate to toDate:

    NSInteger allDaysCount = [self components:NSDayCalendarUnit
        fromDate:fromDate toDate:toDate options:0].day;

We can divide that by the number of days in a week to count just the number of desired weekdays. Since we started counting from a desired weekday, any partial week remainder would also contain the desired weekday, so we need to round up:

    // Adding weekdayRange.length - 1 makes the integer division round up.
    return (allDaysCount + weekdayRange.length - 1) / weekdayRange.length;
}

@end

We can test the method like this:

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = 2012;
components.month = 1;
components.day = 1;
NSDate *fromDate = [calendar dateFromComponents:components];

for (NSUInteger i = 1; i <= 365; ++i) {
    components.day = i;
    NSDate *toDate = [calendar dateFromComponents:components];
    NSLog(@"%@ to %@: %ld Mondays", fromDate, toDate, [calendar countOfWeekday:2 fromDate:fromDate toDate:toDate]);
}

The output starts like this:

2012-08-06 16:27:05.751 tuesdays[81152:403] 0 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-01 06:00:00 +0000
2012-08-06 16:27:05.754 tuesdays[81152:403] 0 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-02 06:00:00 +0000
2012-08-06 16:27:05.756 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-03 06:00:00 +0000
2012-08-06 16:27:05.758 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-04 06:00:00 +0000
2012-08-06 16:27:05.759 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-05 06:00:00 +0000
2012-08-06 16:27:05.760 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-06 06:00:00 +0000
2012-08-06 16:27:05.762 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-07 06:00:00 +0000
2012-08-06 16:27:05.763 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-08 06:00:00 +0000
2012-08-06 16:27:05.763 tuesdays[81152:403] 1 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-09 06:00:00 +0000
2012-08-06 16:27:05.764 tuesdays[81152:403] 2 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-10 06:00:00 +0000
2012-08-06 16:27:05.765 tuesdays[81152:403] 2 Mondays from 2012-01-01 06:00:00 +0000 to 2012-01-11 06:00:00 +0000

This looks correct according to the output of cal 1 2012:

    January 2012
Su Mo Tu We Th Fr Sa
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

(Remember, the toDate is not counted, so there are 0 Mondays from 2012-1-1 to 2012-1-2, even though 2012-1-2 is a Monday.)

Altri suggerimenti

You need to specify your problem. Define what is an weekend? For me weekend is saturday and sunday. So every time a sunday appears it was an weekend(Keep in mind that sunday is not the whole weekend - I just want to simplify the requirements).

So how could you do this in code? There are many ways. One quick approach would be create an Array containing every day in it [Monday,Tuesday,...,Sunday]

Now you want to know how many weekends appear between this Tuesday and Tuesday in 3 weeks. You will get the number three by subtracting targetDateComponent.week-currentDateComponent.week. You just go through this array until Tuesday appeared 3 times and counted all the sundays.

Really simple. I'm not sure if this meets yours problem exactly. But there tons of ways.

Just try to think discreet

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top