Printing Date via NSLog with format - objective-c

Is it possible to print an NSDate object via NSLog without also printing the hour, minute, seconds? What I want it to log is this format yyyy-MM-dd, without the hour, minute, seconds.
I already have an NSDateFormatter with yyyy-MM-dd but when I print the NSDate object via NSLog, it still gives me the hour, minute, second.
Is there a way to do this without creating another string from the date object then logging that string?

You can subclass nsdate and override the description method to return a formatted string. Or write a category to do the same and just call the category method in your log statements.

When NSLog encounters an objective-c object (via the %# token), it calls the method -[NSObject description] and prints the resulting string in its place. NSDate's implementation of that method prints out hours, minutes, and seconds. The only way to have it print something differently is to generate a string yourself using NSDateFormatter.

Related

How to deserialize JSON date to NSDate in objective-c?

I have a Source date string
/Date(1455895287677-0500)/
in objective-c. I need to convert it to format like "2015-01-01 HH:MM:SS"
How can I convert it to Date or NSDate?
I'm using JSONModel, but it seems not working.
Well, it's a non-standard format for dates. Looks like milliseconds since 1970, plus time zone. You DON'T need to convert it to something like "2015-01-01 HH:MM:SS", you want an NSDate.
Take the string, check that it starts with /Date( and ends with )/ and remove these, check whether there is a + or - in between, split into the part before the + or - and the part starting with the + or -, call doubleValue for the first part and divide by 1000 (so you have seconds since 1970), call integerValue for the second part, so you get hours and minutes but in a decimal format. Take that integer value, divide by 100 to get hours, subtract hours times 100 from the number, what remains is minutes. Add hours * 3600 and minutes * 60 to the time. Then [NSDate dateWithTimeIntervalSince1970].
Obviously do some testing, log if there is anything that you didn't expect and make sure you handle it.
As I mentioned in my question, I originally tried to use the JSONModel to deserialize date string, like "/Date(1455895287677-0500)/" but it failed. The reason is that NSDate is not supported by the JSONModel.
However, fortunately, we can achieve this goal by a few steps by modifying and adding methods to JSONModel.
Add [NSDate class] to allowedJSONTypes in JSONModel.m if you use JSONModel(https://github.com/icanzilb/JSONModel) to deserialize your JSON string.
Create a file called JSONValueTransformer+NSDate.m and .h file as well (you can rename them) in folder JSONModelTransformations.
Add this code to your newly created .m file and don't forget write interface in .h file (I planed to add the methods to JSONValueTransformer.m file, but to tell the difference, I decided to create new .m and .h files).
(NSDate ) NSDateFromNSString:(NSString)string {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:APIDateFormat];
return [formatter dateFromString:string];
}
Add method from provided by #jasongregori in Parsing JSON dates on IPhone to your newly created .m file.
The method in step 3 will handle the date format like "2013-08-26T15:23:37.832Z". If the date format is like this /Date(***********-****)/, you have to call method in step 4.

Understanding ObjC bad message examples?

I'm currently reading The Big Nerd Ranch Guide on Objective C programming and I'm having trouble understanding a section in Chapter 13, Objects which is providing bad examples of Messages:
NSDate *now = [NSDate date];
double seconds = [now timeIntervalSince1970];
This is firstly a correct example of using messages in Objc. The first line creates a pointer to an NSDate object using the variable now and the NSDate type declaration. It is now an instance of NSDate. It was explained to me that if you are to print now, it will display the output of the NSDate date method. This is where things start to get a little weird for me. It seems odd that you would have a variable pointing both to an instance, and a function output if printed. But that's okay. Moving on.
The second line creates a variable called seconds, which is of type "double" and is going to obtain a value that the timeIntervalSince1970 method of NSDate instance now outputs.
Here is where the author introduces examples of bad messages:
double testSeconds = [NSDate timeIntervalSince1970];
NSDate *testNow = [now date];
He explains the errors as follows:
First Line:
"The Error is clear, the receiver in this message send is the NSDate
class, so the selector should be the name of an NSDate class method.
This selector is not."
Ok. This makes sense. An invalid method. Next. .
Second Line:
"This error is less clear: It is telling you that NSDate has no
instance method whose name matches the date selector."
Wait, what? Isn't now a pointer to an instance of NSDate? Shouldn't you be able to call the date method from an instance of NSDate? I don't get it.
The book does not explain any more than what I've quoted above, so I'm sure it's something stupid and basic I'm not getting. I hope this isn't too specific or unhelpful to others. I'll delete the submission if asked. Thank you.
The variable now points to an instance of NSDate. The method date is not defined on instances of NSDate but on the class itself. Hence date is a class method and not an instance method. Unlike other programming languages Objective-C does not inherit class methods to their class instances.
Vice versa instance methods cannot be called on classes. This said timeIntervalSince1970 cannot be called on the class NSDate as this method is an instance method. This is due to the circumstances that instances usually manage an instance state. Instance methods do operate on this instance state, namely reading and modifying their instance variables. Back to your example: The instance method timeIntervalSince1970 calculates the difference between 01/01/1970 and a concrete, instantiated date. So if you would be able to call timeIntervalSince1970 on class level there's no chance to calculate a difference of dates as the class NSDate doesn't carry any date information (the instance state!) such as the day, month, year and the time.
To sum up: Instance methods cannot be called on classes. This isn't supported by any programing language I am aware of. Calling class methods on instances is however supported by some programing language although there's typically no need for doing so and sometimes it even lowers code readability. However Objective-C doesn't support those calls neither.

Difference between dot syntax and valueForKey

Please note that update 3 is probably most relevant
Im setting a NSTimeInterval property of a managed object with an nsdate object using setValue:forKey:
When i attempt to get the value I get weird stuff, at runtime this
NSLog(#"[managedObject valueForKey:#\"startTime\"] : %#, [NSDate dateWithTimeIntervalSince1970:[managedObject startTime]]: %#",
[managedObject valueForKey:#"startTime"],[NSDate dateWithTimeIntervalSince1970:[managedObject startTime]]);
Returns
[managedObject valueForKey:#"startTime"] : 2012-07-14 08:13:05 +0000,
[NSDate dateWithTimeIntervalSince1970:[managedObject startTime]]: 1981-07-14 08:13:05 +0000
Update 1
The value returned by [managedObject valueForKey:#"startTime"] is correct. However I would prefer to use [NSDate dateWithTimeIntervalSince1970:[managedObject startTime]] or something similar so that it is more strongly typed.
I believe [managedObject startTime] returns an incorrect value => 363954111.000000 .
However i set it with something like this:
managedObject setValue:1342261311 forKey:#"startTime"
It is worth noting that I am unsure whether this is incorrect because [managedObject valueForKey:#"startTime"] returns a correct NSDate object.
Update 2
I've logged the double values returned by KVC and . syntax.
managedObject.startTime = 363954111.000000
valueForKey timeIntervalSince1970 = 1342261311.000000
Update 3
Okay, I've set up a test, start time is set like this entity.startTime = [[NSDate dateWithTimeIntervalSince1970:1342261311] timeIntervalSince1970]; and end time is set like this [entity setValue:[NSDate dateWithTimeIntervalSince1970:1342261311] forKey:#"endTime"];
When i write them to log i get this start = 1342261311.000000, end = 363954111.000000
It seems that the NSDate object is being unwrapped incorrectly, has anyone seen this before?
The problem here is that valueForKey: is intended to be used with object values, in fact it returns an id.
As a convenience, valueForKey: wraps primitive types (such as integers and doubles) in their NSNumber counterparts.
The reason you see two different values is that valueForKey: returns an id, which essentially is a pointer to the position in memory where the NSNumber happens to be stored. Your code then just takes this arbitrary memory address and somehow interprets it as a double and then constructs an NSDate out of that.
Calling the startTime accessor method directly, on the other hand, returns the double without any further ado.
If you want to use valueForKey:, you can do something like this to get the real value:
NSTimeInterval tiv = [[managedObject valueForKey:#"startTime"] doubleValue];
and then work from there.
I am actually a bit surprised that the compiler doesn't emit a warning about this. Apple's latest compilers have become quite adept at catching problems like this one.
It was a problem with the difference in epochs. NSDate uses Jan 1 2001 as an epoch. So when I was getting the value I was using the unix epoch (1970). That gave me a difference in values.
When KVC unwraps and wraps NSTimeInterval with a NSDate object it uses the NSDate 2001 epoch.
So instead of using dateWithTimeIntervalSince1970
I used dateWithTimeIntervalSinceReferenceDate when getting the value.
NSTimeInterval is a typdef of a double
typedef double NSTimeInterval;
You can not store scalars directly in core data but you either have to wrap them in a NSNumber or in your case it may be easier to use a NSDate.
If startTime is a NSTimeInterval (and not an NSDate), you are comparing two different things there, a double and an NSDAte object.
[managedObject valueForKey:#"startTime"] will return you an NSTimeInterval, a primitive (which you should print with %f by the way).
[NSDate dateWithTimeIntervalSince1970:[managedObject startTime]] will return you a NSDate.
If you really want to comare the two, you should use [NSDate dateWithTimeIntervalSince1970:[managedObject valueForKey:#"startTime"]] to properly compare two NSDate objects.

Calculating time 90 minutes prior to due date/time in Objective C (iPhone app)

This is a completely noobish question, but I spent 2 hours yesterday trying to make it work, and I'm obviously missing something very basic.
What I need to do is take input from user of date/time and count back 90 minutes for an alert.
Could someone please post an example calculation, where you have a var that holds user input and a new var that receives the result of this computation? (all done in Objective C for use in an iPhone app) Thank you!
I suspect you could do something like:
NSDate *alertDate = [userDate dateByAddingTimeInterval:-5400.0];
I think this should work:
NSDate * alarmDate = [NSDate dateWithTimeInterval:5400 sinceDate:userDefinedDate];
NSDate * now = [NSDate date];
NSTimeInterval wait = [now timeIntervalSinceDate:alarmDate];
[self performSelector:#selector(callAlarm) withObject:nil afterDelay:fabs(wait)];
Although I do agree with Nick too, adding your work its much more productive..
Assuming you have a UIDatePicker, your target date will already be in an NSDate object. If it's coming from another source, you're probably ending up with it in an NSDate object, either from a string via an NSDateFormatter or by some other means.
From an NSDate object, you can get an NSTimeInterval relative to some absolute date. That's a C primitive type (it's a double in practice, but obviously don't code to depend on that) that you can do arithmetic directly on. So you can subtract 90 minutes directly from that. There are then various + dateWithTimeInterval... class methods on NSDate that will allow you to get a date from the result.

Converting JSON date(ticks) to NSDate

Does anyone know how to convert a JSON date(ticks) to an NSDate in Objective-C? Can someone post some code?
I'm guessing here but your JSON value is the number of milliseconds since 1970, right? You can use NSDate's dateWithTimeIntervalSince1970: method to return an NSDate object with the correct time. Just make sure to convert the JSON milliseconds number to seconds before passing it to NSDate-- Cocoa uses NSTimeInterval in most places, which represents an interval in seconds.
It goes roughly like this:
// Input string is something like: "/Date(1292851800000+0100)/" where
// 1292851800000 is milliseconds since 1970 and +0100 is the timezone
NSString *inputString = [item objectForKey:#"DateTimeSession"];
// This will tell number of seconds to add according to your default timezone
// Note: if you don't care about timezone changes, just delete/comment it out
NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMT];
// A range of NSMakeRange(6, 10) will generate "1292851800" from "/Date(1292851800000+0100)/"
// as in example above. We crop additional three zeros, because "dateWithTimeIntervalSince1970:"
// wants seconds, not milliseconds; since 1 second is equal to 1000 milliseconds, this will work.
// Note: if you don't care about timezone changes, just chop out "dateByAddingTimeInterval:offset" part
NSDate *date = [[NSDate dateWithTimeIntervalSince1970:
[[inputString substringWithRange:NSMakeRange(6, 10)] intValue]]
dateByAddingTimeInterval:offset];
(from https://gist.github.com/726910)
You'd have to detect the client's locale in order to be able to do that, and unless your client knows how to do that, there's probably not much point.
NSDate's descriptionWithLocale: would be the way you format it for another locale. And timeIntervalSince1970 will go back to the (seconds) since 1970, which you could multiply by 1000 to get ms to return to the client. It's all in the NSDate documentation.
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html
According to this page: http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx ticks begin on Jan 1, 0001 so dateWithTimeIntervalSince1970: is not automatically setup to work with ticks. You can still use this method but should adjust for the difference.