I want to parse a date string that I receive from a web service. However, I sometimes receive the date with decimal component and sometimes without decimal component. Also, sometimes the date comes with a different number of decimal digits.
Assume you got the following date:
NSString *dateString = #"2013-07-22T220713.9911317-0400";
How can remove the decimal values? I want to end up with:
#"2013-07-22T220713-0400";
So I can process it with the DateFormatter that uses no decimal.
You could use a regular expression to match the first occurrence of a decimal followed by numbers, and remove them:
NSString *dateString = #"2013-07-22T220713.9911317-0400";
NSRegularExpression * regExp = [NSRegularExpression regularExpressionWithPattern:#"\\.[0-9]*" options:kNilOptions error:nil];
dateString = [dateString stringByReplacingCharactersInRange:[regExp rangeOfFirstMatchInString:dateString options:kNilOptions range:(NSRange){0, dateString.length}] withString:#""];
Based on #JeffCompton 's suggestion I ended up doing this:
+ (NSDate *)dateFromISO8601:(NSString *)dateString {
if (!dateString) return nil;
if ([dateString hasSuffix:#"Z"]) {
dateString = [[dateString substringToIndex:(dateString.length - 1)] stringByAppendingString:#"-0000"];
}
NSString *cleanDateString = dateString;
NSArray *dateComponents = [dateString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"."]];
if ([dateComponents count] > 1){
NSArray *timezoneComponents = [[dateComponents objectAtIndex:1] componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"-"]];
if ([timezoneComponents count] > 1){
cleanDateString = [NSString stringWithFormat:#"%#-%#", [dateComponents objectAtIndex:0], [timezoneComponents objectAtIndex:1]];
}
}
dateString = [cleanDateString stringByReplacingOccurrencesOfString:#":" withString:#""];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-d'T'HHmmssZZZ";
NSDate *resultDate = [dateFormatter dateFromString:dateString];
return resultDate;
}
This is a modification of some open-source code but I lost the reference to the original code.
The reason for all the modifications is that I am connecting to API's that can give me the date with decimals or without, and sometimes without the : separating HH, mm, and ss.
Related
I am trying to convert a time string using the following code
NSString *origDate = #"2012-12-06T09:27:18+08:00";
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setFormatterBehavior:NSDateFormatterBehavior10_4];
[df setDateFormat:#"yyyy-mm-dd HH:mm:ss VVVV"];
NSDate *convertedDate = [df dateFromString:origDate];
However when I print the convertedDate, it returns me null. My guess is that the Date format U am using does not match. How can I modify the code to make it work? What format can I use to match my string?
EDIT (After referring to apple's documentation)
I checked the date format documentation on apple's page and found the following code
NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[rfc3339DateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
[rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
// Convert the RFC 3339 date time string to an NSDate.
NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
The format above seems to match what I have in the original date string "2012-12-06T09:27:18+08:00". However I am still getting a null value back. Am I getting closer? How else can I update this?
Based on your original input, this format string provided to your date formatter should get the job done:
#"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"
Note: I had tested this under Mac OS X 10.8.2.
The format String will parse on iOS6 (not iOS5 -> nil) but it is useless for output, since the parsed date will loose it's timezone information.
Output will be something like "2012-12-06T17:27:18Z" in iOS6 maybe this is depending on wether the timezone is set to GMT.
my Code:
static NSDateFormatter *gXmlDateFormatter = nil;
// lazy init
+ (NSDateFormatter *)xmlDateFormatter
{
// e.g. updateDateTime="2012-09-18T11:06:19+00:00"
if (gXmlDateFormatter == nil) {
// prepare for parsinf Arinc-ISO-XML-dates input
gXmlDateFormatter = [[NSDateFormatter alloc] init];
gXmlDateFormatter = [NSTimeZone timeZoneForSecondsFromGMT:0];
gXmlDateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
gXmlDateFormatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"; // only parsing! in iOS 6 (iOS5 will parse nil)
// gXmlDateFormatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"; // all iOS but with NO colons in timeZone (add/remove)
}
NSLog(#"gXmlDateFormatter:%#",gXmlDateFormatter);
return gXmlDateFormatter;
}
// there's a problem with the above dateformater and iOS5 creating nil-results
+ (NSDate *)dateFromXMLString:(NSString *)arincDateString
{
NSString *dateString = arincDateString;
// xmlDateStrings may contain a ':' in the timezone part. iOS and Unicode DO NOT
// so always remove the xml-standard colon ':' from the timezone to make it iOS/Unicode compatible
// xml: http://www.w3schools.com/schema/schema_dtypes_date.asp
// iOS: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns)
NSRange zRange = NSMakeRange(arincDateString.length-3, 1);
dateString = [arincDateString stringByReplacingOccurrencesOfString:#":" withString:#"" options:0 range:zRange];
NSDate *date = [self.arincDateFormatter dateFromString:dateString];
if(!date)NSLog(#"PARSING arincDateString:'%#' -> (NSDate*)%# ",arincDateString,date);
return date;
}
+ (NSString *)xmlStringFromDate:(NSDate *)date
{
if( !date ) return nil; // exit on nil date
#autoreleasepool {
NSString *dateString = [self.arincDateFormatter stringFromDate:date];
// iOS5 does not use a ':' in the timeZone part but xml needs it
// so allways add the xml-standard colon ':' into the timezone
NSMutableString *string = [NSMutableString stringWithString:dateString];
if( 22 < string.length ) { // prevent crashing
[string insertString:#":" atIndex:22];
} else {
NSLog(#"date output string too short:%d<22",string.length);
}
dateString = string;
if(!dateString)
NSLog(#"OUTPUT '%#' -> (NSString*)%#",date,dateString);
return dateString;
}
}
I am having some issues with the following function. I have a dictionary with an array of date strings. I would like to loop through them and generate an NSDate object for each string. An example of the date string would be 20Z01NOV2011, where 20Z indicates 8:00 Zulu time, followed by the day,month, year.To make the date extraction easier, I remove the Z and insert a space.
The date formatter seems to work fine the first loop iteration, however fails on the subsequent iterations, however the input string format seems to be fine. Im not sure if there is a memory issue, and the string or formatter needs to be cleared, but I could use a hand correcting it.
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH ddMMMyyyy"];
NSMutableArray *tempDates = [[NSMutableArray alloc] initWithCapacity:[[dict objectForKey:#"time"] count]];
NSMutableArray *tempDateStrings = [[NSMutableArray alloc] initWithCapacity:[[dict objectForKey:#"time"] count]];
for (int i=0; i < [[dict objectForKey:#"time"] count]; ++i) {
NSString *dateString = [[[dict objectForKey:#"time"] objectAtIndex:i] stringByReplacingOccurrencesOfString:#"Z" withString:#" "];
NSDate *date = [timeFormatter dateFromString:dateString];
[tempDates addObject:date];
[timeFormatter setDateFormat:#"EEE h:mm a"];
[tempDateStrings addObject:[timeFormatter stringFromDate:date]];
}
[dict setObject:tempDateStrings forKey:#"dateStrings"];
[dict setObject:tempDates forKey:#"dateObjects"];
Side note, I think you should remove the index from the iteration entirely:
Also, you're resetting the formatter inside the loop…
for (NSString *dateString in [dict objectForKey:#"time"]) {
dateString = [dateString stringByReplacingOccurrencesOfString:#"Z" withString:#" "];
NSDate *date = [timeFormatter dateFromString:dateString];
[tempDates addObject:date];
[timeFormatter setDateFormat:#"EEE h:mm a"]; // RESETING DATE FORMAT - SECOND ITERATION WILL FAIL
[tempDateStrings addObject:[timeFormatter stringFromDate:date]];
}
I suspect you want two formatters, ONE to read the string input, and a SECOND to output the value into the format you like.
It fails on subsequent iterations because you MODIFIED THE FORMAT near the bottom of the loop. What you probably want is two separate formatters, one for one format and one for the other, so you don't have to switch formats back and forth.
I want to be able to get the local date and time for wherever my app is run, based on the iPhone configuration. Specifically I need the date to be of format mm/dd or dd/mm (or dd.mm, mm.dd, dd-mm, mm-dd, etc) depending on the locale, and time is hh:mm. Is this possible with some combination of SDK methods?
Thanks!
I have modified the code so that it just takes the date and time out of the NSDate object with no changes:
NSDate* date = [NSDate date];
NSString* datePart = [NSDateFormatter localizedStringFromDate: date
dateStyle: NSDateFormatterShortStyle
timeStyle: NSDateFormatterNoStyle];
NSString* timePart = [NSDateFormatter localizedStringFromDate: date
dateStyle: NSDateFormatterNoStyle
timeStyle: NSDateFormatterShortStyle];
NSLog(#"Month Day: %#", datePart);
NSLog(#"Hours Min: %#", timePart);
Well, I believe the following code works for what I need:
NSString *dateComponents = #"yMMd";
NSString *dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:[NSLocale currentLocale]];
NSArray *tmpSubstrings = [dateFormat componentsSeparatedByString:#"y"];
NSString *tmpStr;
NSRange r;
if ([[tmpSubstrings objectAtIndex:0] length] == 0) {
r.location = 1;
r.length = [[tmpSubstrings objectAtIndex:1] length] - 1;
tmpStr = [[tmpSubstrings objectAtIndex:1] substringWithRange:r];
} else {
r.location = 0;
r.length = [[tmpSubstrings objectAtIndex:0] length] - 1;
tmpStr = [[tmpSubstrings objectAtIndex:0] substringWithRange:r];
}
NSString *newStr = [[NSString alloc] initWithFormat:#"%# H:mm", tmpStr];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:newStr];
NSString *formattedDateString = [formatter stringFromDate:[NSDate date]];
HI,
I need to display date as "15th November 2010" in iPhone SDK.
How do I do that?
Thanks!
You can use a Date Formatter as explained in this post:
// Given some NSDate* date
NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:#"dd MMM yyyy"];
NSString* formattedDate = [formatter stringFromDate:date];
I believe you can simply just put "th" at the end of the dd in the format string. like this:
#"ddth MMM yyy
but I don't have my Mac in front of me to test it out. If that doesn't work you can try something like this:
[formatter setDateFormat:#"dd"];
NSString* day = [formatter stringFromDate:date];
[formatter setDateFormat:#"MMM yyyy"];
NSString* monthAndYear = [formatter stringFromDate:date];
NSString* date = [NSString stringWithFormat:#"%#th %#", day, monthAndYear];
I know I'm answering something old; but I did the following.
#implementation myClass
+ (NSString *) dayOfTheMonthToday
{
NSDateFormatter *DayFormatter=[[NSDateFormatter alloc] init];
[DayFormatter setDateFormat:#"dd"];
NSString *dayString = [DayFormatter stringFromDate:[NSDate date]];
//yes, I know I could combined these two lines - I just don't like all that nesting
NSString *dayStringwithsuffix = [myClass buildRankString:[NSNumber numberWithInt:[dayString integerValue]]];
NSLog (#"Today is the %# day of the month", dayStringwithsuffix);
}
+ (NSString *)buildRankString:(NSNumber *)rank
{
NSString *suffix = nil;
int rankInt = [rank intValue];
int ones = rankInt % 10;
int tens = floor(rankInt / 10);
tens = tens % 10;
if (tens == 1) {
suffix = #"th";
} else {
switch (ones) {
case 1 : suffix = #"st"; break;
case 2 : suffix = #"nd"; break;
case 3 : suffix = #"rd"; break;
default : suffix = #"th";
}
}
NSString *rankString = [NSString stringWithFormat:#"%#%#", rank, suffix];
return rankString;
}
#end
I grabbed the previous class method from this answer: NSNumberFormatter and 'th' 'st' 'nd' 'rd' (ordinal) number endings
This may be a easy question but i am not able to find the logic.
I am getting the values like this
12.010000
12.526000
12.000000
12.500000
If i get the value 12.010000 I have to display 12.01
If i get the value 12.526000 I have to display 12.526
If i get the value 12.000000 I have to display 12
If i get the value 12.500000 I have to display 12.5
Can any one help me out please
Thank You
Try this :
[NSString stringWithFormat:#"%g", 12.010000]
[NSString stringWithFormat:#"%g", 12.526000]
[NSString stringWithFormat:#"%g", 12.000000]
[NSString stringWithFormat:#"%g", 12.500000]
float roundedValue = 45.964;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2];
[formatter setRoundingMode: NSNumberFormatterRoundUp];
NSString *numberString = [formatter stringFromNumber:[NSNumber numberWithFloat:roundedValue]];
NSLog(numberString);
[formatter release];
Some modification you may need-
// You can specify that how many floating digit you want as below
[formatter setMaximumFractionDigits:4];//2];
// You can also round down by changing this line
[formatter setRoundingMode: NSNumberFormatterRoundDown];//NSNumberFormatterRoundUp];
Reference: A query on StackOverFlow
Obviously taskinoor's solution is the best, but you mentioned you couldn't find the logic to solve it... so here's the logic. You basically loop through the characters in reverse order looking for either a non-zero or period character, and then create a substring based on where you find either character.
-(NSString*)chopEndingZeros:(NSString*)string {
NSString* chopped = nil;
NSInteger i;
for (i=[string length]-1; i>=0; i--) {
NSString* a = [string substringWithRange:NSMakeRange(i, 1)];
if ([a isEqualToString:#"."]) {
chopped = [string substringToIndex:i];
break;
} else if (![a isEqualToString:#"0"]) {
chopped = [string substringToIndex:i+1];
break;
}
}
return chopped;
}