NSDate Bug

Sunday, 10 January 2010

Somebody somewhere say this:

Worst than have nothing, is get something broke.

And this is very true when coding. With the intention to avoid “make the wheel, again” is common the use of system functions included in the programing language or framework, with the assumption that the code reused is best than anything you can make alone — something that is almost always true-.

For BestSeller, I use the Sqlite database, because is the perfect choice in the iPhone. However, Sqlite have as a feature & limitation that everything is stored as string or integers. Not exists dates, booleans, decimals, etc. like in almost any other database like FireBird or Sql Server.

This pose a challenge when is need store dates. The ObjC developers commonly choose between:

  • Store the date with [NSDate timeIntervalSinceDate :], that is the same as a Double, with the problem that is not compatible with the Sqlite datetime functions & is not user-readable at all or:
  • Store the date as a string, something readable & compatible with the functions of Sqlite.

So, I choose the second (who not?) and for avoid ambiguity (something that happen a lot with date manipulations) I use the ISO standard with the format: YYYY-MM-DDTHH:MM:SS.

And how get this with Obj-C? Super-easy, using this code:

:::Objective-C
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];

        strValue = [NSString stringWithFormat:@"'%@'",[dateFormatter stringFromDate: date]];

        [dateFormatter release];

A pice of cake, no? That is what say the official documentation, that is what you found in the examples, the books and that is what work… Until I found a nasty bug that is only visible if the user set their iPhone with the 12 hours format][3]!. This could lead to different nasty problems detailed here.

By fortune, I detect the problem (by mistake!) while doing testing. And the solution? What I found in internet, not elegant! (in the last link the author suggest parse the string & patch the result with a hack) so I have no other option that “fix” it myself. The solution was not obvious to me, but here is it(implemented as a category of NSDate):

:::Objective-C
@implementation NSDate (DateFunctions) 

— (NSString *) formatAsISODate {
    NSDateComponents *dateComp;
    NSCalendar *cal = [NSCalendar currentCalendar];

    dateComp = [cal 
            components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit 
                        | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) 
            fromDate:self];

    return [NSString stringWithFormat:@"%02d-%02d-%02dT%02d:%02d:%02d",dateComp.year,
            dateComp.month,dateComp.day,dateComp.hour,dateComp.minute,dateComp.second];
}

So, the next time you use code that mess with internationalization, be sure you have something broke.


0 comments | 0 pingbacks | tags: , ,


Search

author image

Author: Mario Alejandro M.

Mario Alejandro is the founder of El malabarista ("The Juggler"). Experimented developer with more than 10+ years of experience & creator of software used by more than +2000 users.

Last comments feed Last comments

    No comments on blog

Enter your email address to subscribe to our newsletter