views:

901

answers:

2

I'm aware that there are several Cocoa Touch/iPhone calendar implementations available online, but for certain reasons I'm trying to create my own. I'm running into an issue where the code that I use to lay out the dates (which I represent as instances of UIView placed as subviews into another UIView) is messing up in December.

Currently, what I do is decompose the date into an instance of NSDateComponents, then get the week and weekday properties of the components to figure out the X and Y "positions" of the date view, respectively. I can offset the X position by the week property for the first day of the month I'm laying out.

Brief example: the first day of August 2009 falls on a Saturday, and its date components' week property is 31 (using a Gregorian calendar). Therefore its Y position is 6 and its X position is 0, and the X offset I'll be using is 31. So I can take the second day of August, which is a Sunday, and determine that its X position is 0 and its Y position is week - 31 = 32 - 31 = 1. This way I can lay out a zero-indexed grid of date views for the month of August, and it all goes swimmingly...

...until I try to do the same for December. In December of 2009, apparently the week property wraps to 1 on the 27th (a Sunday), meaning that I wind up trying to place the 27th through the 31st at Y positions -48 or so.

My question is twofold: why does the week property wrap partway into the last month of the year? Is it indexed at the last Sunday of the previous year, rather than the first day of the year? And second, is there a better way to lay out a date grid like this (using other components from an NSDateComponents instance, or anything else I can get from an NSDate and an NSCalendar), or do I just have to add a check for the "last week of year" condition?

+2  A: 

The last few days in December start to belong to week 1 of the next year. (see here)

Instead of using the week property to calculate the weekday positions, I'd just start with Y=0 and then increase it after each Saturday (if your week starts on Sundays)

int x = <calculate x based on the weekday of the 1st of the month>
int y = 0
for (days in month) {
    <add subview for this day>
    x += xOffset
    if (currentWeekday == saturday) {
        x = 0
        y += yOffset
    }
}

P.S.: I'd probably look at the current locale to determine the first weekday:

NSLocale *locale = [NSLocale currentLocale];
NSCalendar *calendar = [locale objectForKey:NSLocaleCalendar];
NSUInteger firstWeekday = [calendar firstWeekday];
Thomas Müller
+1  A: 

I probably wouldn't use weeks in my calculation. You need to lay out the days in rows of 7, which of course we know conceptually as weeks. Practically you should be able to get away just knowing the day of the year and doing a modulus.

Say the year starts on Sunday (column 1) and you want know the position of the 100th day. Well 100 / 7 = 14 with a remainder. So it is in the 14th row. Then do a mod 100 % 7 = 2. So it falls on a Monday (in my example).

Corey Floyd
But is this localizable? I want to be as generic in my calculations as possible, on the off-chance I ever need to use this code in a non-Gregorian setting.
Tim
I think gregorian is a nice base to calculate the rest of your localizations off of. I can't think of a more general way than representing a year as 365 days. How you present the data is completely separate from your underlying implementation. You could create a new category to handle translations from this system to whatever format you may need.
Corey Floyd