The application on which in am currently working is an iPhone app and the backend is in .Net. The iPhone application consumes WCF RestFul API. The database that the server is using is MS SQL and the Client-side in objective-c(xcode4.5,iOS6). I store date in the form of smallDateTime on server-side. On getting this date back in the JSON format, i convert it to NSDate with the below mentioned code.Following is a sample date string that i receive from the server (serverDate=/Date(1356527635798+0500)/).
Following is iPhone side code for conversion.
+ (NSDate *)convertServerDateToNSDate:(NSString *)serverDate
{
serverDate = [serverDate stringByReplacingOccurrencesOfString:#"\"" withString:#""];
serverDate = [serverDate stringByReplacingOccurrencesOfString:#"\\" withString:#""];
if(serverDate == nil)
return nil;
NSDate * nsDate;
NSCharacterSet * tempSet1 = [NSCharacterSet characterSetWithCharactersInString:#"("];
serverDate = [serverDate stringByReplacingOccurrencesOfString:#"-" withString:#"+"];
NSCharacterSet * tempSet2 = [NSCharacterSet characterSetWithCharactersInString:#"+"];
NSRange startRange = [serverDate rangeOfCharacterFromSet:tempSet1];
NSRange endRange = [serverDate rangeOfCharacterFromSet:tempSet2];
NSRange actualRange;
actualRange.location = startRange.location + 1;
actualRange.length = endRange.location - actualRange.location;
NSString * tempString = [serverDate substringWithRange:actualRange];
double timeInSecs = [tempString doubleValue]/1000;
nsDate = [NSDate dateWithTimeIntervalSince1970:timeInSecs];
return nsDate;
}
The Date conversion is perfect on iOS-Simulator 6.0, But date is converted one day less on my ipod. I tried to search it and do it myself but everytime i am getting 1 day less than the actually date.
1) What is the problem ?
2) How can i resolve it ?
3) I ensured that locale is same both on simulator and on iPod.
Any help in this will be much appreciated.
Related
I've been having some issues converting strings to an NSDate, so maybe there's a better/easier way to do this.
I have an NSString of a date formatted like "dd/mm/yyyy", HOWEVER, some do not contain the year and are just "dd/mm".
I'm trying to store the day and month in my SQLite database, so I need to get those components out separately. I have tried converting them into NSDate but because some don't have years, it doesn't match the NSDate format and fails. I've also had issues following examples like this because my original dateString is not in the same format (uses slashes rather than dashes).
Any ideas? Thanks
NSString *dateString = #"01/04/1981";
NSArray *dateComponentsArray = [dateString componentsSeparatedByString:#"/"];
NSString *monthString = [dateComponentArray objectAtIndex:0];
NSString *dayString = [dateComponentsArray objectAtIndex:1];
if ([dateComponentsArray objectAtIndex:2]) {
NSString *yearString = [dateComponentsArray objectAtIndex:2];
}
NSFormatter seems like overkill as it's pretty expensive. If you're sure you're not going to have any changes to the format, this should work.
You could use good ol' fashioned NSScanner.
NSScanner *scanner = [NSScanner scannerWithString:x];
int month, day;
if (
[scanner scanInt:&month] &&
[scanner scanString:#"/" intoString:nil] &&
[scanner scanInt:&day]
) {
NSLog(#"Got month = %d and day = %d", month, day);
}
Check this against the documentation because I'm writing from memory.
SQLite doesn't even have a proper native date type (see my SO recent post on this topic), and to the extent you can store dates in SQLite, it doesn't make sense in the absence of a year. Not sure it makes sense to have a NSDate without a year, either.
Personally, I'd just store three fields, day, month, and year as separate numeric fields in the database, leaving the year blank if you don't know what year the person was born. Thus, just use a simple NSScanner as suggested by #benzado:
int day;
int month;
int year;
NSScanner *scanner = [NSScanner scannerWithString:birthdayString];
if ([scanner scanInt:&month] &&
[scanner scanString:#"/" intoString:nil] &&
[scanner scanInt:&day])
{
// found valid month/day
if ([scanner scanString:#"/" intoString:nil] &&
[scanner scanInt:&year])
{
// found year too
}
}
Or use NSString's componentsSeparatedByString to get it into an array of strings as suggested by #Jacob:
NSString *monthString, *dayString, *yearString;
NSArray *dateComponents = [birthdayString componentsSeparatedByString:#"/"];
if ([dateComponents count] >= 2)
{
monthString = [dateComponents objectAtIndex:0];
dayString = [dateComponents objectAtIndex:1];
// found month and day
if ([dates count] == 3)
{
yearString = [dateComponents objectAtIndex:2];
// found year, too
}
}
You need to figure out what it means when there's no year on the date. Does it assume the current year, or something else? Once you get that figured out, you can append the year to the string and then parse the date.
can't you just check for '/' if its that simple? try to use NSDateFormatter as well, that may help you.
I think this has the answers you need:
Apple iOS Date Formatting guide
I have an NSString *string=#"606" and I want to add a ":" colon after two digits.
The output should look like this: 6:06
It this is possible?
Help would be appropriated.
Thank you very much.
You can add the column between the hours and the minutes like this:
NSString *string = #"606";
NSString *result = [string stringByReplacingCharactersInRange:NSMakeRange(string.length-2, 0) withString:#":"];
NSLog(#"%#", result);
This will give the following results
#"606" => #"6:06"
#"1200" => #"12:00"
#"1406" => #"14:30"
Note: This will only work if the string has 3 or 4 characters, but this is the case according to your question.
Because you do not have two separate objects for hours and minutes, use:
NSString *newTimeString, *hour, *minute;
NSUInteger length = [timeString length];
if (length == 3)
{
hour = [timeString substringToIndex:1];
minute = [timeString substringFromIndex:2];
}
else
{
hour = [timeString substringToIndex:2];
minute = [timeString substringFromIndex:3];
}
newTimeString = [NSString stringWithFormat:#"%#:%#", hour, minute];
I used a long version to illustrate the concept. Basically, use the length of the original string (timeString) to extract the time components and combine them with a colon.
Will it be 2 digits no matter what? Otherwise you could build your custom string from parameters.
NSString *string = [NSString stringWithFormat:#"%#:%#", hours, minutes];
UPDATE
If you just need to add a colon after 1 char, you can do it this way. Although I would suggest finding a safer method as this could be inaccurate if you have a double digit hour.
NSString *hour = [NSString substringToIndex:1]; // double check the index
NSString *min = [NSString substringFromIndex:1]; // double check the index
NSString *time = [NSString stringWithFormat:#"%#:%#", hour, min];
Hopefully this will help.
NSString * str=[zoneDict objectForKey:#"name"];
NSLog(#"==========string zone::==========%#",str);
// str="(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersbur";
How can I get the 3:00 value from the above string?
NSString *str = #"(GMT -3:00) Baghdad, Riyadh, Moscow, St. Petersbur";
NSRange endRange = [str rangeOfString:#")"];
NSString *timeString = [str substringWithRange:NSMakeRange(5, endRange.location-5)];
NSRange separatorRange = [timeString rangeOfString:#":"];
NSInteger hourInt = [[timeString substringWithRange:NSMakeRange(0, separatorRange.location)] intValue];
NSLog(#"Hour:%d",hourInt);
Rather than trying to extract the time offset from the string, is there any way you could store actual time zone data in your zoneDict? For example you could store NSTimeZone instances instead.
If all you have is the string, you could use an NSRegularExpression object and extract the relevant information using a regular expression instead.
If you could explain further what you're trying to do then there may be an alternative way to achieve what you want.
I like to use -[NSString componentsSeparatedByString]:
NSString *str = #"(GMT -3:00) Baghdad, Riyadh, Moscow, St. Petersbur";
NSArray *myWords = [myString componentsSeparatedByString:#")"];
NSString *temp1 = [myWords objectAtIndex:0];
if ([temp1 rangeOfString:#"-"].location == NSNotFound) {
NSArray *temp2 = [temp1 componentsSeparatedByString:#"+"];
NSString *temp3 = [temp2 objectAtIndex:1];
NSLog(#"Your String - %#", temp3);
}
else {
NSArray *temp2 = [temp1 componentsSeparatedByString:#"-"];
NSString *temp3 = [temp2 objectAtIndex:1];
NSLog(#"Your String - %#", temp3);
}
Output:
Your String - 3:00
Using regular expressions is the better option in my view (if you are forced to extract the '3' only). The regular expression string would contain something like "\d?" but don't quote me on that, you'll have to look up the exact string. Perhaps someone on here could provide the exact string.
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.
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:×tampString];
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];
}
}
}