Mac OS X Reference Library Apple Developer Connection spyglass button

Calendrical Calculations

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.

Adding Components to a Date

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];

Temporal Differences

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];

Converting from One Calendar to Another

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

Did this document help you? Yes It's good, but... Not helpful...