NSDate provides the absolute scale and epoch for dates and times, which can then be rendered into a particular calendar, for calendrical calculations or user display. To perform calendrical calculations, you typically need to get the component elements of a date, such as the year, the month, and the day.
You use the dateByAddingComponents:toDate:options: method to add components of a date (such as hours or months) to an existing date. You can provide as many components as you wish. Listing 1 shows how to calculate a date an hour and a half in the future.
Listing 1 An hour and a half from now
NSDate *today = [[NSDate alloc] init]; |
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init]; |
[offsetComponents setHour:1]; |
[offsetComponents setMinutes:30]; |
// Calculate when, according to Tom Lehrer, World War III will end |
NSDate *endOfWorldWar3 = [gregorian dateByAddingComponents:comps toDate:today options:0]; |
Components to add can be negative. The following example shows how you can get the Sunday in the current week (using a Gregorian calendar).
Listing 2 Getting the Sunday in the current week
NSDate *today = [[NSDate alloc] init]; |
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; |
// Get the weekday component of the current date |
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:today]; |
/* |
Create a date components to represent the number of days to subtract from the current date. |
The weekday value for Sunday in the Gregorian calendar is 1, so subtract 1 from the number of days to subtract from the date in question. (If today's Sunday, subtract 0 days.) |
*/ |
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init]; |
[componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 1)]; |
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0]; |
/* |
Optional step: |
beginningOfWeek now has the same hour, minute, and second as the original date (today). |
To normalize to midnight, extract the year, month, and day components and create a new date from those components. |
*/ |
NSDateComponents *components = |
[gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) |
fromDate: beginningOfWeek]; |
beginningOfWeek = [gregorian dateFromComponents:components]; |
The following example illustrates how you can calculate the first moment of the week (as defined by the calendar's locale):
Listing 3 Getting the beginning of the week
NSDate *today = [[NSDate alloc] init]; |
NSDate *beginningOfWeek = nil; |
BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek |
interval:NULL forDate: today]; |
You use components:fromDate:toDate:options: to determine the temporal difference between two dates in units other than seconds (which you could calculate with the NSDate method timeIntervalSinceDate:). Listing 4 shows how to get the number of months and days between two dates using a Gregorian calendar.
Listing 4 Getting the difference between two dates
NSDate *startDate = ...; |
NSDate *endDate = ...; |
NSCalendar *gregorian = [[NSCalendar alloc] |
initWithCalendarIdentifier:NSGregorianCalendar]; |
NSUInteger unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit; |
NSDateComponents *components = [gregorian components:unitFlags |
fromDate:startDate |
toDate:endDate options:0]; |
NSInteger months = [components month]; |
NSInteger days = [components day]; |
To convert components of a date from one calendar to another—for example, from Gregorian to Hebrew—you first create a date object from the components using the first calendar, then you decompose the date into components using the second calendar. Listing 5 shows how to convert date components from one calendar to another.
Listing 5 Converting date components from one calendar to another
NSDateComponents *comps = [[NSDateComponents alloc] init]; |
[comps setDay:6]; |
[comps setMonth:5]; |
[comps setYear:2004]; |
NSCalendar *gregorian = [[NSCalendar alloc] |
initWithCalendarIdentifier:NSGregorianCalendar]; |
NSDate *date = [gregorian dateFromComponents:comps]; |
[comps release]; |
[gregorian release]; |
NSCalendar *hebrew = [[NSCalendar alloc] |
initWithCalendarIdentifier:NSHebrewCalendar]; |
NSUInteger unitFlags = NSDayCalendarUnit | NSMonthCalendarUnit | |
NSYearCalendarUnit; |
NSDateComponents *components = [hebrew components:unitFlags fromDate:date]; |
NSInteger day = [components day]; // 15 |
NSInteger month = [components month]; // 9 |
NSInteger year = [components year]; // 5764 |
Last updated: 2009-07-21