Tuesday, April 19, 2011

NSDateComponents and a better way to handle dates

Handling dates in objective-c can be quite difficult if you don't use the right tools.
And the best tools are for sure the NSDateComponents class. This class is available to both Mac and iOS development, and it makes handling dates much more simple.
Suppose that you need to get the month number of a date. If you don't know NSDateComponents, a way to do that is create a NSDateFormatter and set the format only for the month and get a string that you could convert to a number. Simple  like that. Actually this is far from simple, and far from optimal and far from good programming practices.
Using NSDateComponents things get much easier.
Just create a NSCalendar, like in this statement
NSCalendar* calendar = [NSCalendar currentCalendar];
and set which components you want to retrieve, these are the options:
  • NSEraCalendarUnit,
  • NSYearCalendarUnit,
  • NSMonthCalendarUnit,
  • NSDayCalendarUnit,
  • NSHourCalendarUnit,
  • NSMinuteCalendarUnit,
  • NSSecondCalendarUnit,
  • NSWeekCalendarUnit,
  • NSWeekdayCalendarUnit,
  • NSWeekdayOrdinalCalendarUnit,
You can specify which components you want using a statement like this one
NSUInteger flags = NSMonthCalendarUnit | NSDayCalendarUnit;
And later you just need to call
NSDateComponents* components = [calendar components:flags fromDate:someDate];
and you will have (in this case) the day and the month of the someDate variable.
To get these values just call the day and month methods from the components object, and you will get an NSInteger.
Also if you want to add some time to a date, like an hour, or a day, or 65 days,4 hours and 3 minutes, if you dont use NSDateComponents, you would end up using something like this:
[someDate addTimeInterval:60*60] //add an hour to someDate
To and an hour this is the simplest way, but and if you need to add 65 days,4 hours and 3 minutes? things would get a lot harder, wouldn't it?
Using NSDateComponents this is done like a breeze :)
You will need the calendar again, and then you instantiate a NSDateComponents, like this:
NSDateComponents *components = [[NSDateComponents alloc] init];
and you set the time you want to add, like in our example:
[components setDay:65];
[components setHour:4];
[components setMinutes:3];
and you call:
NSDate *futureDate = [calendar dateByAddingComponents:components toDate:[NSDate date] options:0];
You can also find the distance between two dates using the NSDateComponents. It is as simple as the other functions:
You set the components you want to track, like this code:
NSUInteger flags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *components = [calendar components:flags fromDate:startDate toDate:endDate options:0];
NSInteger months = [components month];
NSInteger days = [components day];
You see, the NSDateComponents can make you life dealing with dates a lot simpler :)