Wednesday, December 14, 2011

iOS - incrementing a date value from a string input

One of the enhancements I'm making my iOS app is to add scheduling for a review of particular words. This review date is actually based on the amount of time it takes to answer a given question - the longer it takes, the quicker the review should be scheduled. Another consideration is the internal format in which dates are held by SQLLite, which is a string in yyyy-MM-dd format. This is helpful because now the input and output of the problem solution is limited to string manipulation.

So the input to our method is effectively the number of seconds it took to answer the question. We'll add the input date for flexibility - we could assumed it's today, but this is a trade-off for re-usability.

So, the first thing we need to do is take the string input date and convert it to an iOS date.

The key is the NSDateFormatter object, which has both the "stringFromDate" and the "dateFromString" methods. So, looking at an example from http://iphonedevelopertips.com/cocoa/date-formatters-examples-take-3.html, we adapt it a bit.

Example:

NSString *dateStr = @"20081122";

// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyyMMdd"];
NSDate *date = [dateFormat dateFromString:dateStr];

// Convert date object to desired output format
[dateFormat setDateFormat:@"EEEE MMMM d, YYYY"];
dateStr = [dateFormat stringFromDate:date];
[dateFormat release];


We want to turn this into a method in our Utils class, which will also take the number of days:

+ (NSString *) addDaysToDate:(NSString *) inDate daysToAdd: (int) daysToAdd;

So, the first thing to do is take the code above and adapt it to convert the "yyyy-MM-dd" input string to a date.

// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd"];
NSDate *date = [dateFormat dateFromString:inDate];


Well tackle adding days to the date in a moment. For now, assume we've done that and just want to convert it back to the same format it came in as:

// Convert date object to desired output format
// The date format is already the way we want it

NSString *dateStr = [dateFormat stringFromDate:newDate];
[dateFormat release];
return dateStr;


The only remaining question is how to increment an instance of NSDate in iOS. Reviewing the docs, it looks like this might be the one that we're looking for:

dateByAddingTimeInterval:

Returns a new NSDate object that is set to a given number of seconds relative to the receiver.
- (id)dateByAddingTimeInterval:(NSTimeInterval)seconds


However, it's always worth a google check to make sure that's right. As it turns out, it isn't. It doesn't handle daylight savings time, for one thing. According to StackOverflow, the correct solution is this:


+ (NSDate *)getForDays:(int)days fromDate:(NSDate *)date
{
NSDateComponents *components= [[NSDateComponents alloc] init];
[components setDay:days];

NSCalendar *calendar = [NSCalendar currentCalendar];
return [calendar dateByAddingComponents:components toDate:date options:0];
}


So, once we add this to our Utils class, the call should look like something like this:


NSDate *newDate = [Utils getForDays: daysToAdd fromDate: date];

Here's the final (hopefully) product:

+ (NSString *) addDaysToDate:(NSString *) inDate daysToAdd: (int) daysToAdd
{

// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd"];
NSDate *date = [dateFormat dateFromString:inDate];


NSDate *newDate = [Utils getForDays: daysToAdd fromDate: date];

// Convert date object to desired output format
// The date format is already the way we want it

NSString *dateStr = [dateFormat stringFromDate:newDate];
[dateFormat release];
return dateStr;
}

No comments:

Post a Comment