How to deserialize JSON date to NSDate in objective-c? - 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.

Related

Printing Date via NSLog with format

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.

using NSDate to find the DATE from string

I am having problem finding date from string that is formatted using NSDateFormatter
Now, I am using this code:
NSDate *afterDate=[NSDate dateWithNaturalLanguageString:balanceDateAfter.stringValue];
This code returning date with GeorgianCalendar format but I want it in PersianCalendar.
I think if I use this code :
NSDate *afterDate=[NSDate dateWithNaturalLanguageString:balanceDateAfter.stringValue locale:];
It will return true date format but I don't know how can I use locale to set appropriate date formatter ( or my system locale ).
balanceDateAfter in above codes is an NSTextfield with NSDateFormatter.
NSDates do not have a calendar. An NSDate represents an absolute moment in time as defined by the difference between that moment and the first instant of 1st January 2001 in GMT. Basically, it's a positive or negative number of seconds, nothing more.
If you have an appropriate formatter assigned to the text field, you should get its value using -objectValue, not -stringValue. That way, you will be given the NSDate directly and you won't need to parse the string yourself.

nil result from NSDateFormatter with 0's in format string

I'm getting a date from a webservice back in the form MM00yyyy -- it is just the two-digit month, followed by two 0's, and then the four-digit year. When I do this:
NSString *expDate = #"12001975";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM00yyyy"];
NSDate postDate = [dateFormat dateFromString:expDate];
[dateFormat dateFromString] returns nil for some reason. I have also tried MMddyyyy, and MM'0''0'yyyy, with no success either way. I am converting a similar date, except the 0's are actually the day with no problem using the same method.
To get this working, I would just use the following pattern MMHHyyyy. Since you need only the date and not neccessarily the hour, the HH will use the 00 to set the time as zeroth hour and hence you will get the date that you are looking for. Again this is just a hack and a workaround only to solve your current problem.
Have a look at the Date Formatting Guide from Apple. The section "Use Format Strings to Specify Custom Formats" lists all the different standards the are supported by various iOS versions for specifying a format string. I would say that "00" is not allowed, so that is the reason why "MM00yyyy" is failing. Similarly, "MMddyyyy" is also failing because no day can be "00".
I don't know if you can have more luck with UNIX functions, as the Apple doc suggests:
For date and times in a fixed, unlocalized format, that are always guaranteed to use the same calendar, it may sometimes be easier and more efficient to use the standard C library functions strptime_l and strftime_l.
Be aware that the C library also has the idea of a current locale. To guarantee a fixed date format, you should pass NULL as the loc parameter of these routines. This causes them to use the POSIX locale (also known as the C locale), which is equivalent to Cocoa's en_US_POSIX locale, as illustrated in this example.
struct tm sometime;
const char *formatString = "%Y-%m-%d %H:%M:%S %z";
(void) strptime_l("2005-07-01 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(#"NSDate is %#", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]);
// Output: NSDate is 2005-07-01 12:00:00 -0700
Getting the format strings right seems much more like art than science. I suggest you make a new string without the 00 in it and then have your DateFromatter process that with "MMyyyy".
While this might not be the "correct" way to do it, it should solve your problem pretty quickly.
The zeros are unsupported symbols. Apple supports the following characters for date formatting: http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns See the day section.

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.