Julia asks:
How do I get Objective-C to display the number of seconds since my birth?
When you often gnaw on complex and frustrating questions – like I often do – it is rather refreshing to work out a good answer to such a simple question.
In Objective-C dates are represented by NSDate objects. Objects for arbitrary dates are created by means of NSDateComponents and an NSCalendar. The date components are essentially a structure where you specify a day, month and year number. The calendar then knows how to map these components to an actual date. Different calendars will have a different result, most of the western world is using the gregorian calendar which is the counting the years since the birth of Christ.
// create empty components NSDateComponents *comps = [[NSDateComponents alloc] init]; // set the component values [comps setYear:1997]; [comps setMonth:5]; [comps setDay:11]; [comps setHour:12]; [comps setMinute:12]; [comps setSecond:0]; // create a gregorian calendar for mapping NSCalendar *g = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; // derive a date object from the calendar with these components NSDate *dateofBirth = [g dateFromComponents:comps]; |
After this we have an NSDate object that the variable dateofBirth is pointing to.
There is an extra simple and a safer method to determine the number of seconds that passed since this point in time.
NSTimeInterval
Time intervals in Objective-C are represented by values of type NSTimeInterval. Those are not object, but rather a number. More precisely it is a double precision floating point value representing the an amount of seconds and second fractions. Internally dates are for the most part represented as the number of seconds that passed since an arbitrary reference date. Apple uses Jan 1st, 1970 00:00:00 for this for dates, and Jan 1st, 2001 in a few other cases.
NSDate has several instance methods that will give you the time interval between this date and another.
- – [NSDate timeIntervalSinceDate:] – seconds between the other date and this date
- – [NSDate timeIntervalSinceReferenceDate] – seconds between the first instant of 1 January 2001, GMT and this date
- – [NSDate timeIntervalSince1970] – seconds between the first instant of 1 January 1970, GMT and this date
- – [NSDate timeIntervalSinceNow] – seconds between this date and the current time
The last one of these instance methods sounds like what we want:
// get seconds from birth until "now" NSTimeInterval secs = -[dateofBirth timeIntervalSinceNow]; NSLog(@"%d", (int)secs); |
Note the use of the negation. The reason for this is that because “now” is a higher value than the “birth time” it would be negative.
You might think now that you could also use one of these methods to get the time interval between the birth day and an arbitrary date. Stop! Hold your horses!
Time intervals are not appropriate for this kind of date math. The reason being that this gives incorrect values for different time zones or if there are Daylight Savings Time switches between the dates. I explained the proper method for adding a time interval to a date in a previous post.
Date Math with NSDateComponents
Rather than using NSTimeInterval for answering the original question, you can also use NSDateComponents to do that. You see, this class is not only good for creating dates, but also to determine the amount of date units (e.g. seconds, days, months, et al) between two dates, again based on a specific calendar.
// create date object with current time NSDate *now = [NSDate date]; // get seconds from birth time object until now object NSDateComponents *diff = [g components:NSSecondCalendarUnit fromDate:dateofBirth toDate:now options:0]; NSLog(@"%d", (int)[diff second]); |
We again use the previously created gregorian calendar und ask it to give us a new NSDateComponents object where we are interested in the “Seconds Calendar Unit”.
If you execute both methods in succession you see that the result is the same. At the time of this writing slightly more than 526.3 million seconds.
Conclusion
NSDateComponents – in combination with a calendar to base calculations on – is a versatile class. You can create NSDate instances for specific points in time. You can also use it to derive the difference between two date objects in an arbitrary calendar unit.
As an exercise try to modify the above to count the number of weeks or years between birthday and today.
Categories: Q&A