How do I get the current date in Cocoa

Viewed 131526

I'm getting started developing for the iPhone and as such I am looking at different tutorials online as well as trying some different things out myself. Currently, I'm trying to create a countdown until midnight. To get the number of hour, minutes, and seconds, I do the following (which I found somewhere):

NSDate* now = [NSDate date];

int hour = 23 - [[now dateWithCalendarFormat:nil timeZone:nil] hourOfDay];
int min = 59 - [[now dateWithCalendarFormat:nil timeZone:nil] minuteOfHour];
int sec = 59 - [[now dateWithCalendarFormat:nil timeZone:nil] secondOfMinute];
countdownLabel.text = [NSString stringWithFormat:@"%02d:%02d:%02d", hour, min,sec];

However, each place I use -dateWithCalendarFormat:timeZone: I get the following error:

warning: 'NSDate' may not respond to '-dateWithCalendarFormat:timeZone:'
(Messages without a matching method signature will be assumed to return 'id' and accept '...' as arguments.)
warning: no '-hourOfDay' method found
error: invalid operands to binary - (have 'int' and 'id')

This seems like something very simple. What am I missing?

Also, I've noticed at different places and at different times the asterisk (*) is located either right after the time NSDate* now or right before the variable NSDate *now. What is the difference in the two and why would you use one versus the other?

14 Answers

You have problems with iOS 4.2? Use this Code:

NSDate *currDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:@"dd.MM.YY HH:mm:ss"];
NSString *dateString = [dateFormatter stringFromDate:currDate];
NSLog(@"%@",dateString);

-->20.01.2011 10:36:02

You must use the following:

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [gregorian components:(NSHourCalendarUnit  | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:yourDateHere];
NSInteger hour = [dateComponents hour];
NSInteger minute = [dateComponents minute];
NSInteger second = [dateComponents second];
[gregorian release];

There is no difference between NSDate* now and NSDate *now, it's just a matter of preference. From the compiler perspective, nothing changes.

You can also use:


CFGregorianDate currentDate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), CFTimeZoneCopySystem());
countdownLabel.text = [NSString stringWithFormat:@"%02d:%02d:%02.0f", currentDate.hour, currentDate.minute, currentDate.second];
CFRelease(currentDate); // Don't forget this! VERY important

I think this has the following advantages:

  1. No direct memory allocation.
  2. Seconds is a double instead of an integer.
  3. No message calls.
  4. Faster.

You need to do something along the lines of the following:

NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSHourCalendarUnit fromDate:now];
NSLog(@"%d", [components hour]);

And so on.

Also, I've noticed at different places and at different times the asterisk (*) is located either right after the time NSDate* now or right before the variable NSDate *now. What is the difference in the two and why would you use one versus the other?

The compiler doesn't care, but putting the asterisk before the space can be misleading. Here's my example:

int* a, b;

What is the type of b?

If you guessed int *, you're wrong. It's just int.

The other way makes this slightly clearer by keeping the * next to the variable it belongs to:

int *a, b;

Of course, there are two ways that are even clearer than that:

int b, *a;

int *a;
int b;

NSDate* now and NSDate *now are the same thing: a pointer to an NSDate object.

You probably want to use descriptionWithCalendarFormat:timeZone:locale: rather than dateWithCalendarFormat: — the latter returns an NSCalendarDate, which the docs say is scheduled to be deprecated at some point.

Here's another way:

NSDate *now = [NSDate date];

//maybe not 100% approved, but it works in English.  You could localize if necessary
NSDate *midnight = [NSDate dateWithNaturalLanguageString:@"midnight tomorrow"]; 

//num of seconds between mid and now
NSTimeInterval timeInt = [midnight timeIntervalSinceDate:now];
int hours = (int) timeInt/3600;
int minutes = ((int) timeInt % 3600) / 60;
int seconds = (int) timeInt % 60;

You lose subsecond precision with the cast of the NSTimeInterval to an int, but that shouldn't matter.

There is no difference in the location of the asterisk (at in C, which Obj-C is based on, it doesn't matter). It is purely preference (style).

Related