JSON date to NSDate and back - objective-c

I have a JSON date, e.g: 1295804021525, which is the number of milliseconds from 1970.
I have written the following code to convert this number into an NSDate:
long long seconds = [[payload valueForKey:#"starttime"]longLongValue]/1000;
NSDate *somedate = [NSDate dateWithTimeIntervalSince1970:seconds];
Which does work and returns the correct date. First I'm wondering if this is the best way of doing the conversion.
Next I am wondering how to convert back to the milliseconds format and then put into the url to send back to the server.
I have:
long long date = [somedate timeIntervalSince1970] * 1000;
NSString *urlString = [NSString stringWithFormat:#"http://someurl?since=%qi",date];
Again this seems to work but I was wondering how I could get the same functionality using NSNumber.

With your original conversion, you're losing sub-second precision. You may want to do something like
CFTimeInterval seconds = [[payload valueForKey:#"starttime"] doubleValue] / 1000.0;
The second snippet should be fine.
I'm not sure why you think using NSNumber would help in any fashion. With the modification I mentioned, both these code snippets are straightforward and should work just fine.

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.

Converting an NSNumber to NSTimeInterval

I've converted an NSTimeInterval to an NSNumber in order to store it in NSUserDefaults. I used the numberWithDouble method like this:
NSNumber *savedTime = [NSNumber numberWithDouble:timeInterval];
I'm retrieving the information in another view, but I'm running into an issue. The number doesn't seem to want to convert properly. I know the number is carrying over, because I am able to view the number in this label, and it shows up properly:
timeLabel.text = [NSString stringWithFormat:#"%f", [[[userDefaults objectForKey:groupTitleForReference] objectForKey:#"time"] doubleValue]];
but when I go to set the interval to the double value, it doesn't work. I'm using this:
interval = [[[userDefaults objectForKey:groupTitleForReference] objectForKey:#"time"] doubleValue];
All variables are properly declared in the header. Any idea why it's not working?
Thanks,
David
In both cases, you use
[[[userDefaults objectForKey:groupTitleForReference] objectForKey:#"time"] doubleValue]
to get the double value. You need to concentrate on what might be different. Off the top of my head, look at:
Is interval correctly declared as a double or NSTimeInterval? Show us how and where you declare interval.
When you display interval to check its value, are you displaying it correctly. I've been known to do this by accident
NSTimeInterval interval = ....
NSLog(#"%#", interval);
Show us the code you use to inspect the interval and its output.
Has userDefaults changed?
Has groupTitleForReference changed.
EDIT
Another thing to check
If interval is a global make sure the declaration in the header is of the form
extern NSTimeInterval interval;
If you omit extern, you'll get a separate variable called interval in every file that includes the header.

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.

NSString to NSDate with float values

I'm developing an OS X desktop application which will track time for a car racing event.
The difference between pilots can be very small, so the collected data for each lap has a floating point value for the seconds:
bestLap = #"00:01:39.5930000"
But I need to compare each pilot's time and sort it. I'm trying to convert it to a NSDate object, using NSDateFormatter and I couldn't manage to make it work
Is it possible to convert a string like that to a NSDate? If so, how can I compare and sort an array containing NSDates
Thanks
An NSDate is used to represent a date, not a time interval.
Also, if the purpose is just to sort them, there is no need to convert the string into an NSDate or NSTimeInterval since they are already lexicographically ordered if a time interval is shorter than the other in your format.
That means, calling -sortUsingSelector: is enough.
[theMutableArrayOfLaps sortUsingSelector:#selector(compare:)];
As KennyTM says, lexicographic sorting is enough if all you need is ordering. If you really want to get a numeric value for comparison & reporting purposes, you can break the string up into components and convert to a double something like this:
NSArray* parts = [bestLap componentsSeparatedByString:#":"];
double bestLapInSeconds = [[parts objectAtIndex:0] doubleValue] * 3600 // hours
+ [[parts objectAtIndex:1] doubleValue] * 60 // minutes
+ [[parts objectAtIndex:2] doubleValue]; // seconds
(Note that this just blithely assumes that the original string conforms to an "H:M:S" format without any error checking. You should not normally do this in real life!)

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.