NSDateFormatter and setDateFormat: and SSS - objective-c

Using NSDateFormatter, here is my input :
00:20:11,026 (NSString)
And here is the output i want :
"00:20:11,026"; (NSDate)
but what I obtained is :
"1970-01-01 00:20:11 +0100" (NSDate)
// SSS is missing and there is too much information...
Here is what i coded :
...
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm:ss,SSS"];
[dateFormatter dateFromString:#"00:20:11,026"];
...

Well, first of all, your NSDateFormatter is just fine.
Judging by the output, it looks like you're just NSLogging an actual NSDate object, and expecting the format to be representative of the NSDateFormatter that was used to create it. All NSDate objects will be formatted the same if you NSLog them, regardless of whether you got them from an NSDateFormatter or not. The "1970-01-01 00:20:11 +0100" string that you are worried about is actually supplied by NSDate's implementation of the -description method.
So my guess is that, while the fractional seconds (SSS) are missing from your log statement, they actually are present and accounted for in the NSDate object. Furthermore, the "too much information" is also just an artifact of the default description provided by NSDate. I'm fairly certain your actual NSDate contains all of the information you want it to.

Related

Objective C programming, passing message to NSDate

I am following a book for objective-C and came across this example to print the current date using NSLog statement. I am confused why the NSDate class was not instantiated(alloc and init) before passing the date message to it.
NSDate * pointerToIt = [NSDate date];
Further down the code another message was passed to this pointer..
[pointerToIt timeIntervalSince1970];
What I knew is as long as the pointer holds the address to instance of a class messages can be sent to it but the class was never instantiated and still the messages are being passed. Can someone throw some light on this for me ?
The date is a somewhat special way to get the current date. It is a static method on the NSDate class which does the following:
Creates and returns a new date set to the current date and time.
This method uses the default initializer method for the class, init.
Your code is pretty much the same as in the docs:
NSDate *today = [NSDate date];
Therefore the today object is in fact implicitly correctly initalized.
[NSDate date] did the alloc and init for you. If you refer to the documentation you will read.
Creates and returns a new date set to the current date and time.
[NSDate date] is a class factory method. Internally, it would look something like this:
+ (instancetype)date {
return [[self alloc] init];
}

initialize an instance in objective-C with alloc and init

I am learning Objective-C and I've just read about alloc and int methods. Before this point,when I wanted to create an instance of NSDate for example, I coded:
NSDate *now = [NSDate date];
Now I saw that the above can be written like this
NSDate *now = [[NSDate alloc] init];
Are the above do the same thing? As i have understood (hopefully correct) the first one creates and instance of NSDate, by sending the message date to the class NSDate. The second one, it just allocates space for the instance and initialize it, so that it is ready to work.
You would think the two things you list were definitely not the same thing based on a background knowledge of Objective-C, if you weren't familiar with NSDate. But in fact, they are the same thing in this case.
[NSDate date] is calling an NSDate class method that returns an NSDate object set to the current date and time.
Normally, a method call like [[NSDate alloc] init] would instantiate a new default object of the type requested, so you might expect that this would not be set to any date/time. However, the default NSDate object is in fact initialised with the current date and time, as discussed in the documentation, so in this particular case—they are the same thing.
As an aside, as with most NSObjects, you can also just call [NSDate new] to get the same effect as [[NSDate alloc] init] (and thus the same effect in this case as [NSDate date]).

Why do I have to define the class of the pointer?

I'm studying Objc with the book from BigNerdRanch 'Objective-C Programming from Aaron Hillegass' and there's this thing that keeps puzzling me.
I understand that the complier needs to know what kind of variable I'm talking about so i have to declare the var type before assigning a value.
int myNum = 10;
Fine. But when it comes to ObjC classes, what's the reason for declaring the type of pointer if I have to declare it right after the =, when I alloc and init it?
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
Obviously the *dateFormatter object is an istance of NSDateFormatter, I wrote it in the allocation. Why do i have to declare it at the beginning too?
'Cause if I try to do something like
NSString *timeZone = [NSTimeZone systemTimeZone];
Xcode clearly warns me with 'Incompatible pointer types initializing 'NSString *' with an expression of type 'NSTimeZone *'.
I feel like I'm missing something. Sorry if it's a dumb question, trying to learn.
Here the real question is rather "Why do I have to define the correct class of the pointer?"...
The answer is: you may want to use the variable in some other context as well. If you message [NSTimeZone systemTimeZone] directly, then the compiler may be able to deduce the type, but what if you message the variable? If you go with the weaker-typed
id tz = [NSTimeZone systemTimeZone];
then there's much less opportunity for the compiler to check for errors if you use tz where an NSTimeZone * is expected than it could if you declared it as NSTimeZone *tz.
As an even clearer example, suppose you have a method:
- (NSTimeZone *) userSpecifiedTimeZone {
id timeZone = [NSTimeZone timeZoneWithAbbreviation:self.timeZoneName];
if (timeZone == nil)
timeZone = [NSTimeZone timeZoneWithName:self.timeZoneName];
if (timeZone == nil)
timeZone = self.timeZoneName;
return timeZone;
}
See the bug?
Xcode won't catch it, since it's perfectly valid to assign any object to a variable of type id, and to return an id from a method whose return type is any object type, and to subsequently assign that id to another id variable, or try to send messages to it, in the calling code.
You'll find this bug—if you don't catch it early with your own human eyes—only at run time, and only when the user enters a bogus time zone name, and you then try to use that time zone name (wrongly returned as this method's result) as an NSTimeZone object.
Compare to the statically-typed version:
- (NSTimeZone *) userSpecifiedTimeZone {
NSTimeZone *timeZone = [NSTimeZone timeZoneWithAbbreviation:self.timeZoneName];
if (timeZone == nil)
timeZone = [NSTimeZone timeZoneWithName:self.timeZoneName];
if (timeZone == nil)
timeZone = self.timeZoneName; //Clang calls shenanigans here
return timeZone;
}
Clang rightly objects that assigning an NSString * to a variable typed as NSTimeZone * is suspicious.
You don't have to define the class of the pointer, but the potential otherwise for bugs like the one shown above is why we do it.
But when it comes to ObjC classes, what's the reason for declaring the
type of pointer if I have to declare it right after the =, when I
alloc and init it?
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
You're not declaring the type of pointer twice. There's a lot going on in this statement. The first occurrence of 'NSDateFormatter' is telling the compiler that dataformatter is a pointer to this type of object, whereas the second occurrence of 'NSDateFormatter' is calling the 'alloc' method in the NSDateFormatter class. Same word, two completely different meanings.
The first thing that happens is [NSDateFormatter alloc] which is calling the (class) method 'alloc' in the 'NSDateFormatter' class. This returns an (empty) instance of an NSDateFormatter object in which the method 'init' is called. A pointer to the resultant object is then stored in your 'dateFormatter' variable, and we tell the compiler that this is a pointer to an NSDateFormatter object.
Think of it like this:
NSDateFormatter *dateFormatter; Create a pointer to an NSDateFormatter object.
newDate = [NSDateFormatter alloc]; Create an empty NSDateFormatter object by calling the class method alloc in NSDateFormatter
[newDate init]; Initialise it by calling the onject's 'init' method
dateformatter = *newDate; Assign a pointer to it to my variable.

How to know what timezone to set for an NSDateFormatter when converting from an NSDate

I have a function which converts an NSString in RFC3339 to NSDate using an NSDateFormatter, but I don't know how to take account of the timezone doing the reverse.
The relevant part of the string to NSDate conversion is:
// The result of a call to systemTimeZone is cached by the app automatically, if the user changes it that change isn't
// reflected unless resetSystemTimeZone is called to clear the cache.
[NSTimeZone resetSystemTimeZone];
NSLocale *enUSPOSIXLocale;
enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
if ([fromString hasSuffix:#"Z"] || [fromString hasSuffix:#"z"])
{
[sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
}
else
{
[sRFC3339DateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
}
[sRFC3339DateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
My question is, when converting in the other direction from an NSDate to an NSString, how do I know what to call setTimeZone with? When going from string to NSDate its by looking at the absense/presense of Z. But if I have an NSDate how do I know what time zone to set the formatter to?
Your NSDate is stored as UTC/GMT timezone. So when you are converting that to a string, you pick the time zone you want the string displayed in. There is no "right" answer. It's whatever you want to display.

NSDateFormatter Incompatible Type Error

I am receiving the following error in Xcode:
warning: incompatible Objective-C types 'struct NSDate *', expected 'struct NSString *' when passing argument 1 of 'setUpdate:' from distinct Objective-C type
The error happens when I am trying to save the formatted string to myObj.update
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'Z'"];
//myObj is an object with instance variable 'update' as a NSString string
myObj.update = [formatter dateFromString:#"2011-03-17T18:15:05Z"];
[formatter release];
I know I am doing something wrong that is minor but can't pinpoint. Thanks for the help! :)
dateFromString: returns an instance of NSDate, not a string. You need to make your update property an NSDate. The compiler is basically telling you that the method is returning a date, but you're trying to assign that to a string property, and that's just not gonna be healthy!