How get a datetime column in SQLite with Objective C - iphone

How do you get a datetime column in SQLite with Objective C?
I have a table with 4 fields: pk, datetime, value1 and value2. pk (primary key), value1 and value2 are integers so I am using:
int value1 = sqlite3_column_int(statement, 2);
int value1 = sqlite3_column_int(statement, 3);
But what should I use for datetime?

In SQLite, there is no date/time column type per se, so one ends up representing dates either as Julian date values (real columns) or in strings (text columns). SQLite is also very particular in how dates are represented in strings, yyyy-MM-dd HH:mm:ss (only).
These are some methods that I wrote for working with SQLite dates from Objective-C. These methods are implemented in a category on NSDate.
Be sure to check out the functionality that SQLite offers for working with Julian dates. I have found these to be quite useful (http://www.sqlite.org/lang_datefunc.html). A function for deriving an NSDate's julianDay is included in the code example.
It looks like this subject was also covered here.
Persisting Dates to SQLite3 in an iPhone Application
+ (NSDate *) dateWithSQLiteRepresentation: (NSString *) myString;
{
NSAssert3(myString, #"%s: %d; %s; Invalid argument. myString == nil", __FILE__, __LINE__, __PRETTY_FUNCTION__);
return [[self sqlLiteDateFormatter] dateFromString: myString];
}
+ (NSDate *) dateWithSQLiteRepresentation: (NSString *) myString timeZone: (NSString *) myTimeZone;
{
NSString * dateWithTimezone = nil;
NSDate * result = nil;
NSAssert3(myString, #"%s: %d; %s; Invalid argument. myString == nil", __FILE__, __LINE__, __PRETTY_FUNCTION__);
NSAssert3(myTimeZone, #"%s: %d; %s; Invalid argument. myTimeZone == nil", __FILE__, __LINE__, __PRETTY_FUNCTION__);
dateWithTimezone = [[NSString alloc] initWithFormat: #"%# %#", myString, myTimeZone];
result = [[self sqlLiteDateFormatterWithTimezone] dateFromString: dateWithTimezone];
[dateWithTimezone release];
return result;
}
+ (NSString *) sqlLiteDateFormat;
{
return #"yyyy-MM-dd HH:mm:ss";
}
+ (NSString *) sqlLiteDateFormatWithTimeZone;
{
static NSString * result = nil;
if (!result) {
result = [[NSString alloc] initWithFormat: #"%# zzz", [self sqlLiteDateFormat]];
}
return result;
}
+ (NSDateFormatter *) sqlLiteDateFormatter;
{
static NSDateFormatter * _result = nil;
if (!_result) {
_result = [[NSDateFormatter alloc] init];
[_result setDateFormat: [self sqlLiteDateFormat]];
}
return _result;
}
+ (NSDateFormatter *) sqlLiteDateFormatterWithTimezone;
{
static NSDateFormatter * _result = nil;
if (!_result) {
_result = [[NSDateFormatter alloc] init];
[_result setDateFormat: [self sqlLiteDateFormatWithTimeZone]];
}
return _result;
}
- (NSString *) sqlLiteDateRepresentation;
{
NSString * result = nil;
result = [[NSDate sqlLiteDateFormatter] stringFromDate: self];
return result;
}
- (NSTimeInterval) unixTime;
{
NSTimeInterval result = [self timeIntervalSince1970];
return result;
}
#define SECONDS_PER_DAY 86400
#define JULIAN_DAY_OF_ZERO_UNIX_TIME 2440587.5
- (NSTimeInterval) julianDay;
{
return [self unixTime]/SECONDS_PER_DAY + JULIAN_DAY_OF_ZERO_UNIX_TIME;
}
+ (NSDate *) dateWithJulianDay: (NSTimeInterval) myTimeInterval
{
NSDate *result = [self dateWithTimeIntervalSince1970: (myTimeInterval - JULIAN_DAY_OF_ZERO_UNIX_TIME) * SECONDS_PER_DAY];
return result;
}

If you can define the database, then ou could also use REAL (SQLite data type) as the type for the datetime, then load it with sqlite3_column_double(). This will return a variable of the type double.
Then you can use [NSDate dateWithTimeIntervalSince1970:double_value] to get an NSDate object.

Please note that the category solution above has a problem in that it is subject to the locale settings on the user's device. For example, for midnight April 5th 2010 sqlLiteDateRepresentation above would return 2010/04/05 00:00:00 for most people's machines, however I have encountered a scenario where a user's locale settings caused the same function to produce "2010/04/05 12:00:00 a.m." which when used in my query does not return any rows. This seems to follow from the documentation of NSDateFormatter: "In general, you are encouraged to use format styles (see timeStyle, dateStyle, and NSDateFormatterStyle) rather than using custom format strings, since the format for a given style reflects a user’s preferences. Format styles also reflect the locale setting." Although I didn't see a good way to use the timeStyle/dateStyle to get the same format as yyyy/MM/dd HH:mm:ss that SQLite seems to need. I fear your best bet is likely a custom solution where you ensure that the time is definitely written in 24H format, don't allow locale settings to cause bugs.

If you just want to get an NSDate from an SQLite datetime field, where dateTime is the field returned from the database:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [dateFormatter dateFromString:dateTime];

Now Work!
NSString *dateValueS = [[NSString alloc]
initWithUTF8String:(char*) sqlite3_column_text(statement,2)];

Related

random BAD ACCESS when saving user defaults

I'm simply trying to save this array to the user defaults and it will crash at random. Sometimes it works, sometimes it gives me the EXC_BAD_ACCESS. Am I not releasing something properly?
- (void)setTextValue:(NSString *)valueText indexToSet:(NSUInteger)index
{
[self.pageData replaceObjectAtIndex:index withObject:valueText];
[[NSUserDefaults standardUserDefaults] setObject:self.pageData forKey:#"mynotes"];
}
Here is the method that i've determined is causing the errors. It was a method already created by Xcode that I added my own custom code to.
- (nbookDataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
nbookDataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:#"nbookDataViewController"];
if (self.pageData.count > 0 && index < self.pageData.count)
{
NSString *val = (NSString *)[self.pageData objectAtIndex:index];
dataViewController.dataObject = val;
}
else
{
NSDate *date = [NSDate date];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MMMM d, YYYY"];
NSString *dateString = [dateFormat stringFromDate:date];
//[dateFormat release];
[self.pageData addObject:dateString];
dataViewController.dataObject = (NSString *)[self.pageData objectAtIndex:index];
}
dataViewController.myModel = (nbookModelController *)self;
dataViewController.dIndex = index;
//[self.mySaveData setObject:self.pageData forKey:#"mynotes"];
return dataViewController;
}
This tip will allow you code to break on the exception and let you check directly why this is happening:
https://stackoverflow.com/a/616526/46970

NSDate if Statement

I was wondering how I could use NSDate within an if statement - I want to update a UILabel depending what the date is, currently I have the following code to determine the date but don't know how to actually get this within an if statement.
NSDate* date = [NSDate date];
NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:#"dd/MM/yyyy"];
NSString *dateString = [formatter stringFromDate:date];
dateLabel.text = dateString;
if (dateString == #"25/05/2012") {
NSLog(#"It's the 25th!");
}
else {
NSLog(#"Not it's not...");
}
Thanks a lot!
If you want to compare two strings use isEqualToString:
if ([dateString isEqualToString:#"25/05/2012"]) {
NSLog(#"It's the 25th!");
}
else {
NSLog(#"Not it's not...");
}
isEqualToString: in NSString class reference
if you want to compare two NSDate use isEqualToDate:
[date1 isEqualToDate:date2]
isEqualToDate: in NSDate class reference
To compare strings you can use isEqualToString: not == (with this you're comparing the pointers).
To compare dates you can use isEqualToDate:.
Depending on what you actually want to achieve you can use next calls:
NSDate:
- (BOOL)isEqualToDate:(NSDate *)anotherDate
- (NSComparisonResult)compare:(NSDate *)anotherDate
NSString:
- (BOOL)isEqualToString:(NSString *)aString
As has been noted, == checks for pointer equality. If you want to match the contents of an NSString or NSDate, or any other class of object, check that class' documentation for isEqual... and compare... methods. (NSDate has isEqualToDate: and compare:; NSString has isEqualToString: and compare: as well as several more specialized comparison methods.
However, depending on just what your aim is in matching dates, comparing NSDates with isEqualToDate: or checking the result of compare: against NSOrderedSame might not do what you want. An NSDate doesn't represent a whole calendar day but rather a specific moment in time. So if you have an NSDate representing 5/25/2012 1:53:13 AM PDT and one representing 5/25/2012 1:55:01 AM PDT, they will be equal or compare as NSOrderedSame.
What you're going for with the NSDateFormatter and string comparison will sort of work for checking whether two NSDates represent the same calendar day (presuming you compare string contents with isEqualToString: instead of using ==), but it's sort of kludgy and will fail in certain edge cases that are more common than you think. Apple provides APIs specifically for such comparisons; there's a section in the Date and Time Programming Guide that explains them well.
NSDate provides
- (BOOL)isEqualToDate:(NSDate *)anotherDate
- (NSComparisonResult)compare:(NSDate *)anotherDate
Here is a category (found here http://webd.fr/637-comparer-deux-nsdate) that offers a neat way to compare NSDates:
#import <Foundation/Foundation.h>
#interface NSDate (Compare)
-(BOOL) isLaterThanOrEqualTo:(NSDate*)date;
-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date;
-(BOOL) isLaterThan:(NSDate*)date;
-(BOOL) isEarlierThan:(NSDate*)date;
//- (BOOL)isEqualToDate:(NSDate *)date; already part of the NSDate API
#end
And the implementation:
#import "NSDate+Compare.h"
#implementation NSDate (Compare)
-(BOOL) isLaterThanOrEqualTo:(NSDate*)date {
return !([self compare:date] == NSOrderedAscending);
}
-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date {
return !([self compare:date] == NSOrderedDescending);
}
-(BOOL) isLaterThan:(NSDate*)date {
return ([self compare:date] == NSOrderedDescending);
}
-(BOOL) isEarlierThan:(NSDate*)date {
return ([self compare:date] == NSOrderedAscending);
}
#end
Simple to use:
if([aDateYouWant ToCompare isEarlierThanOrEqualTo:[NSDate date]]) // [NSDate date] is now
{
// do your thing ...
}

conversion Nsstring

Hi all guys ,I am new in objective c and I need help, I read from my xml
file and I want convert my NSString to bool and NSString to date and
Nsstring to long
NSArray *names = [partyMember elementsForName:#"price"];
if (names.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [names objectAtIndex:0];
price = firstName.stringValue;
} else continue;
NSArray *names1 = [partyMember elementsForName:#"date"];
if (names1.count > 0) {
GDataXMLElement *firstName1 = (GDataXMLElement *) [names1 objectAtIndex:0];
date = firstName1.stringValue;
NSArray *names1 = [partyMember elementsForName:#"test"];
if (names1.count > 0) {
GDataXMLElement *firstName1 = (GDataXMLElement *) [names1 objectAtIndex:0];
test = firstName1.stringValue;
For the BOOL
A string is NO if its either nil or length 0. Otherwise its YES.
NSDateFormatter's dateFromString will convert strings to dates. You set it up with a c style formatter.
For the long use longValue as in long long myval = [mystring longLongValue];
NSString has several converters
– doubleValue
– floatValue
– intValue
– integerValue
– longLongValue
– boolValue
Use as required.
In the future, please first look at Apple's documentation. It is very thorough. In the page on NSString, you can see there is a boolValue method and a longLongValue method. You can read the specifics in the documentation, but those will handle your bool and long cases.
As for converting a date, there are many stackoverflow questions on that topic, this one here should answer your question.
I'm usually not one to say RTFM, but in this case the information was very easily found with a couple quick searches.
To convert NSString to BOOL use below method.
BOOL boolValue = [myString boolValue];
For converting to long use longLongValue: method of NSString.
For NSString to NSDate , use below as reference code.
NSString *dateString = #"2011-07-13";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSString itself has functions to get bool and float values.
See reference.
To get date, u need to look at NSDateFormatter.

Optimise slow code - enumeration of dictionary

I have the following code that decodes a JSON string into an array of objects that I can then use in a UITableView.
At first I thought the JSON decoding was the slow part but it appears that it is not as the "Dictionary Done" appears almost immediately.
Any ideas on how to get that code to be a little faster?
-(void)parseJSON:(NSString *)jsonData{
NSLog(#"Start parsing");
NSDictionary *deserializedData = [jsonData objectFromJSONString];
NSLog(#"Dictionary Done");
NSArray *flights = [deserializedData valueForKeyPath:#"flights.flight"];
NSMutableArray *localArray = [[NSMutableArray alloc] init ];
NSString *lastFlightno =#"";
for (NSDictionary *flight in flights){
ArchiveFlight *aFlight = [[ArchiveFlight alloc] initWithFlightno:[flight objectForKey:#"flightno"] route:[flight objectForKey:#"route"]];
aFlight.flightID = [flight objectForKey:#"primary_key"];
aFlight.timeStamp = [aFlight niceDate:[flight objectForKey:#"timestamp"]];
if (![lastFlightno isEqualToString:aFlight.flightno]) {
[localArray addObject:aFlight];
}
lastFlightno =aFlight.flightno;
[aFlight release];
}
NSLog(#"End Parsing");
[self loadupTable:localArray];
self.flightArray = localArray;
[localArray release];
}
EDIT: Added timestamps
Timestamps of the NSLogs as follows...
2011-04-26 13:22:36.104 App[1778:707] Finished request
2011-04-26 13:22:36.109 App[1778:707] Start parsing
2011-04-26 13:22:36.128 App[1778:707] Dictionary Done
2011-04-26 13:22:37.713 App[1778:707] End Parsing
Sample of the JSON...
{"flights":[{"flight":{"flightno":"RYR54WP","timestamp":"2011-04-26 12:13:04","route":"EGNX-LEAL","primary_key":"836453"}},{"flight":{"flightno":"RYR24LU","timestamp":"2011-04-26 09:14:03","route":"EVRA-EGNX","primary_key":"831318"}},{"flight":{"flightno":"RYR39WH","timestamp":"2011-04-26 05:33:03","route":"EGNX-EVRA","primary_key":"825492"}},{"flight":{"flightno":"RYR7PX","timestamp":"2011-04-25 20:07:03","route":"LELC-EGNX","primary_key":"816703"}},{"flight":{"flightno":"RYR2VB","timestamp":"2011-04-25 16:57:06","route":"EGNX-LELC","primary_key":"810900"}},{"flight":{"flightno":"RYR3JN","timestamp":"2011-04-25 12:36:04","route":"GCTS-EGNX","primary_key":"802631"}},{"flight":{"flightno":"RYR8GV","timestamp":"2011-04-25 06:07:03","route":"EGNX-GCTS","primary_key":"792945"}},{"flight":{"flightno":"RYR82QR","timestamp":"2011-04-24 19:42:04","route":"EPKK-EGNX","primary_key":"783306"}},{"flight":{"flightno":"RYR51PV","timestamp":"2011-04-24 16:31:05","route":"EGNX-EPKK","primary_key":"777835"}},{"flight":{"flightno":"RYR53AQ","timestamp":"2011-04-24 14:09:05","route":"LIME-EGNX","primary_key":"773572"}},{"flight":{"flightno":"RYR1CX","timestamp":"2011-04-24 11:02:05","route":"EGNX-LIME","primary_key":"768285"}},{"flight":{"flightno":"RYR9ZW","timestamp":"2011-04-24 08:21:04","route":"LEGE-EGNX","primary_key":"764624"}},{"flight":{"flightno":"RYR63BC","timestamp":"2011-04-24 05:48:02","route":"EGNX-LEGE","primary_key":"761726"}},{"flight":{"flightno":"RYR7PX","timestamp":"2011-04-23 19:39:03"
Formatted sample:
{
"flights":[
{
"flight":{
"flightno":"RYR54WP",
"timestamp":"2011-04-26 12:13:04",
"route":"EGNX-LEAL",
"primary_key":"836453"
}
},
{
"flight":{
"flightno":"RYR24LU",
"timestamp":"2011-04-26 09:14:03",
"route":"EVRA-EGNX",
"primary_key":"831318"
}
}
]
}
EDIT 2:
So here is "niceDate" that is causing the slowdown!
-(NSString *)niceDate:(NSString *)oldDate{
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init]autorelease];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *sourceDate = [formatter dateFromString:oldDate];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterFullStyle];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
NSString *timeString = [dateFormatter stringFromDate:sourceDate];
return [NSString stringWithFormat:#"%#",timeString];
}
Some things that come to mind:
NSArray *flights = [deserializedData valueForKeyPath:#"flights.flight"];
Do you need to use KVC? What is the structure of your JSON data?
ArchiveFlight *aFlight = [[ArchiveFlight alloc] initWithFlightno:[flight objectForKey:#"flightno"] route:[flight objectForKey:#"route"]];
aFlight.flightID = [flight objectForKey:#"primary_key"];
aFlight.timeStamp = [aFlight niceDate:[flight objectForKey:#"timestamp"]];
You always create an instance of ArchiveFlight and parse the timestamp…
if (![lastFlightno isEqualToString:aFlight.flightno]) {
[localArray addObject:aFlight];
}
…even though you don’t have to do that all the time. Depending on how many repeated flightnos you have, this can make a noticeable difference.
Why not read [flight objectForKey:#"flightno"], compare it to lastFlightno and, if and only if they’re different, create an instance, add it to the array, and release it?
Edit: Try the following KVC-free code:
NSArray *flights = [deserializedData objectForKey:#"flights"];
NSMutableArray *localArray = [[NSMutableArray alloc] init ];
NSString *lastFlightno =#"";
for (NSDictionary *flightWrapper in flights) {
NSDictionary *flight = [flightWrapper objectForKey:#"flight"];
NSString *flightno = [flight objectForKey:#"flightno"];
if (! [flightno isEqual:lastFlightno]) {
// create instance, add it to the array, release the instance
}
}
Edit: You’re creating and (auto)releasing two instances of NSDateFormatter inside this method. In general this would be okay, but since it is being executed >1K times there are two considerations: a) you’re creating/using/releasing those two instances >1K times when, in fact, you don’t have two, b) you should use an autorelease pool in your loop.
You should make this method a class method (or a function) since it doesn’t depend on the state of an instance of that class. Your formatters would be class (static) variables. For instance:
#implementation ArchiveFlight
static NSDateFormatter *formatter1; // choose better names!
static NSDateFormatter *formatter2;
+ (void)initialize {
if (self == [ArchiveFlight class]) {
formatter1 = [[NSDateFormatter alloc] init];
[formatter1 setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
formatter2 = [[NSDateFormatter alloc] init];
[formatter2 setDateStyle:NSDateFormatterFullStyle];
[formatter2 setTimeStyle:NSDateFormatterLongStyle];
}
}
+ (NSString *)niceDate:(NSString *)oldDate {
NSDate *sourceDate = [formatter1 dateFromString:oldDate];
NSString *timeString = [formatter2 stringFromDate:sourceDate];
return timeString;
// why +stringWithFormat:? It’s not necessary!
// return [NSString stringWithFormat:#"%#",timeString];
}
This fixes item a) but you really should use an autorelease pool inside your loop because the Cocoa methods you’re using return autoreleased objects. By using an autorelease pool for each iteration of your loop, you reduce the memory footprint of your code — although this could decrease performance as well. I suggest you try both with and without an inner autorelease pool.
for (NSDictionary *flightWrapper in flights) {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
…
[pool drain];
}

Parsing JSON dates on IPhone

Forgive me as I'm new to Objective C.
I am getting back dates from a .NET webservice in the /Date(xxxxxxxxxxxxx-xxxx)/ format. I'm looking for some direction on how to best parse this into an NSDate object. I've tried using dateWithTimeIntervalSince1970 on it but it comes back with a date in the year 1969 for a date I know is in 2006.
Looking for some direction on the proper way to handle JSON dates.
Thanks in advance!
I just wrote this for iOS 4.0+ (because it uses NSRegularExpression). It handles dates with or without timezone offsets. Seems to work pretty well, what do you think?
+ (NSDate *)mfDateFromDotNetJSONString:(NSString *)string {
static NSRegularExpression *dateRegEx = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dateRegEx = [[NSRegularExpression alloc] initWithPattern:#"^\\/date\\((-?\\d++)(?:([+-])(\\d{2})(\\d{2}))?\\)\\/$" options:NSRegularExpressionCaseInsensitive error:nil];
});
NSTextCheckingResult *regexResult = [dateRegEx firstMatchInString:string options:0 range:NSMakeRange(0, [string length])];
if (regexResult) {
// milliseconds
NSTimeInterval seconds = [[string substringWithRange:[regexResult rangeAtIndex:1]] doubleValue] / 1000.0;
// timezone offset
if ([regexResult rangeAtIndex:2].location != NSNotFound) {
NSString *sign = [string substringWithRange:[regexResult rangeAtIndex:2]];
// hours
seconds += [[NSString stringWithFormat:#"%#%#", sign, [string substringWithRange:[regexResult rangeAtIndex:3]]] doubleValue] * 60.0 * 60.0;
// minutes
seconds += [[NSString stringWithFormat:#"%#%#", sign, [string substringWithRange:[regexResult rangeAtIndex:4]]] doubleValue] * 60.0;
}
return [NSDate dateWithTimeIntervalSince1970:seconds];
}
return nil;
}
I was in the same boat whilst using json-framework which doesn't support the date format as it's not official JSON. My source is from an API built using JSON.Net. This is what I came up with:
- (NSDate*) getDateFromJSON:(NSString *)dateString
{
// Expect date in this format "/Date(1268123281843)/"
int startPos = [dateString rangeOfString:#"("].location+1;
int endPos = [dateString rangeOfString:#")"].location;
NSRange range = NSMakeRange(startPos,endPos-startPos);
unsigned long long milliseconds = [[dateString substringWithRange:range] longLongValue];
NSLog(#"%llu",milliseconds);
NSTimeInterval interval = milliseconds/1000;
return [NSDate dateWithTimeIntervalSince1970:interval];
}
I don't have the appended portion in the date format that you do so I haven't dealt with that like the answer above. No error catching either, it's all new to me at this point.
I actually found the snippet with NSRegularExpression pretty useful, till i came up with another solution that uses NSCharecterSet for stipping off the milliseconds.
+ (NSDate*) dateFromJSONString:(NSString *)dateString
{
NSCharacterSet *charactersToRemove = [[ NSCharacterSet decimalDigitCharacterSet ] invertedSet ];
NSString* milliseconds = [dateString stringByTrimmingCharactersInSet:charactersToRemove];
if (milliseconds != nil && ![milliseconds isEqualToString:#"62135596800000"]) {
NSTimeInterval seconds = [milliseconds doubleValue] / 1000;
return [NSDate dateWithTimeIntervalSince1970:seconds];
}
return nil;
}
Saves a lot of the manual string processing and makes the code much cleaner.
As a .NET programmer learning Objective-C I had the same problem when I tried to consume a .Net WebService.
At first I thought I would be able to use the NSDateFormatter...
I found a really good reference for it's symbols here, but I quickly realized that I needed to convert the number from milliseconds to seconds.
I wrote the code to do it...
I'm still learning Obj-C but I dont think It should've been this hard...
- (NSDate *) getJSONDate{
NSString* header = #"/Date(";
uint headerLength = [header length];
NSString* timestampString;
NSScanner* scanner = [[NSScanner alloc] initWithString:self];
[scanner setScanLocation:headerLength];
[scanner scanUpToString:#")" intoString:&timestampString];
NSCharacterSet* timezoneDelimiter = [NSCharacterSet characterSetWithCharactersInString:#"+-"];
NSRange rangeOfTimezoneSymbol = [timestampString rangeOfCharacterFromSet:timezoneDelimiter];
[scanner dealloc];
if (rangeOfTimezoneSymbol.length!=0) {
scanner = [[NSScanner alloc] initWithString:timestampString];
NSRange rangeOfFirstNumber;
rangeOfFirstNumber.location = 0;
rangeOfFirstNumber.length = rangeOfTimezoneSymbol.location;
NSRange rangeOfSecondNumber;
rangeOfSecondNumber.location = rangeOfTimezoneSymbol.location + 1;
rangeOfSecondNumber.length = [timestampString length] - rangeOfSecondNumber.location;
NSString* firstNumberString = [timestampString substringWithRange:rangeOfFirstNumber];
NSString* secondNumberString = [timestampString substringWithRange:rangeOfSecondNumber];
unsigned long long firstNumber = [firstNumberString longLongValue];
uint secondNumber = [secondNumberString intValue];
NSTimeInterval interval = firstNumber/1000;
return [NSDate dateWithTimeIntervalSince1970:interval];
}
unsigned long long firstNumber = [timestampString longLongValue];
NSTimeInterval interval = firstNumber/1000;
return [NSDate dateWithTimeIntervalSince1970:interval];
}
Hopefully someone can provide a better Obj-C solution.
If not I may keep this or look for a way to change the serialization format in .NET
EDIT:
About that JSON DateTime format...
If you have any control on the service it would probably be best to convert the date to a string in your DataContract objects.
Formatting to RFC1123 seems like a good idea to me right now. As I can probably pick it up easily using a NSDateFormatter.
Quote from Rick Strahl
There's no JavaScript date literal and Microsoft engineered a custom date format that is essentially a marked up string. The format is a string that's encoded and contains the standard new Date(milliseconds since 1970) value.
Theory: MS encoded the C# DateTime in JSON as milliseconds since 1970.
Solution:
NSString*
dateAsString = #"/Date(1353720343336+0000)/";
dateAsString = [dateAsString stringByReplacingOccurrencesOfString:#"/Date("
withString:#""];
dateAsString = [dateAsString stringByReplacingOccurrencesOfString:#"+0000)/"
withString:#""];
unsigned long long milliseconds = [dateAsString longLongValue];
NSTimeInterval interval = milliseconds/1000;
NSDate* date = [NSDate dateWithTimeIntervalSince1970:interval];
This is the shortest solution I can think of.
Use an NSDateFormatter's dateFromString: method after setting the date format.
-(NSString*)convertToUTCTime:(NSString*)strDate{
NSDate *currentDate = [NSDate date];
myDate = [commonDateFormatter dateFromString: strDate];
NSTimeInterval distanceBetweenDates = [currentDate timeIntervalSinceDate:myDate];
return [self stringFromTimeInterval:distanceBetweenDates];
}
- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
NSInteger ti = (NSInteger)interval;
NSInteger minutes = (ti / 60) % 60;
NSInteger hours = (ti / 3600);
if (hours > 24) {
NSInteger days = hours/24;
if (days > 30) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEE d MMM, h:mm a"];
//[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"IST"]];
NSString *daydate = [dateFormatter stringFromDate:myDate];
return daydate;
}
else{
return [NSString stringWithFormat:#" %2ldd",(long)days];
}
}else{
if (hours == 0 && minutes < 1) {
return [NSString stringWithFormat:#"Today"];
}
else if (hours == 0 && minutes < 60){
return [NSString stringWithFormat:#"%2ldm ",(long)minutes];
}
else{
return [NSString stringWithFormat:#" %2ldh",(long)hours];
}
}
}