Friday, April 29, 2011

RFC 3339 dates and iOS parsing

I am currently developing an iPad client for a Java-based Web app that uses JAX-RS for the Web interface (Jersey is the implementation of JAX-RS being used).

I ran into an interesting problem yesterday regarding the parsing of RFC 3339 dates (example - 2011-04-28T16:28:03.065-07:00) in iOS.  Apple nicely documents how to parse RFC 3339 dates, but leaves out one detail.

There is an issue with the timezone containing the colon ':' character. The character must be removed for the RFC 3339 date to be able to be parsed into an NSDate instance.  I spent some time until I found this as a comment in a date parsing class.  Removing the colon from the timezone portion (i.e. 2011-04-28T16:28:03.065-0700) allows NSDateFormatter to parse the textual representation of the date into an NSDate instance.

I also ran into a cute issue: sometimes the fractional seconds aren't included, most likely because the value is 0.  I had to use two NSDateFormatter instances, one using 'yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSZ' the other 'yyyy'-'MM'-'dd'T'HH':'mm':'ssZ' for the date without milliseconds.

Here is the final version of the code to parse RFC 3339 date text into an NSDate instance.

    NSMutableString* dateString = [rfc3339DateTimeString mutableCopy];
    NSRange range = [dateString rangeOfString:@":" options:NSBackwardsSearch];
    if (range.location != NSNotFound) {
        // remove the last ':'
        [dateString deleteCharactersInRange:range];
    }
   
    // Convert the RFC 3339 date time string to an NSDate.
    static NSDateFormatter* rfc3339DateFormatter1 = nil;
    static NSDateFormatter* rfc3339DateFormatter2 = nil;
    if (rfc3339DateFormatter1 == nil) {
        rfc3339DateFormatter1 = [[NSDateFormatter alloc] init];
        NSLocale* enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        [rfc3339DateFormatter1 setLocale:enUSPOSIXLocale];
        [rfc3339DateFormatter1 setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSZ"];
        [rfc3339DateFormatter1 setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

        rfc3339DateFormatter2 = [[NSDateFormatter alloc] init];
        [rfc3339DateFormatter2 setLocale:enUSPOSIXLocale];
        [rfc3339DateFormatter2 setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
        [rfc3339DateFormatter2 setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

        [enUSPOSIXLocale release];
    }
   
    NSDate* date = [rfc3339DateFormatter1 dateFromString:dateString];
    if (date == nil) {
        date = [rfc3339DateFormatter2 dateFromString:dateString];
    }
   
    return date;

Tuesday, April 26, 2011

Upgrade of MySQL 5.1 to 5.5 on Mac OS X

I recently upgraded my existing MySQL 5.1 instance to 5.5 on my Mac (Mac OS X 10.6.7).  On my first try MySQL would not start after the upgrade.  I received the error '/usr/local/mysql/bin/mysqld: Table 'mysql.plugin' doesn't exist'.

After some Web searching I found that I had run into the same exact issues identified by this MySQL bug.  The last comment was the key to my being able to successfully upgrade MySQL: use the my.cnf template files distributed with the MySQL 5.5 version.

I've upgraded twice, just to make sure the solution worked.  Here is what I did:

1) shutdown the MySQL 5.1 instance: sudo /Library/StartupItems/MySQLCOM/MySQLCOM stop
2) rename the existing my.cnf file (one may not exist): sudo mv /etc/my.cnf /etc/my.cnf.51
3) download and install MySQL 5.5: I used the DMG distribution, running mysql-5.5.11-osx10.6-x86_64.pkg first, MySQLStartupItem.pkg second, MySQL.prefPane third.
4) copied the MySQL 5.5 my-large.cnf file into /etc: sudo cp /usr/local/mysql/support-files/my-large.cnf /etc/my.cnf
5) started MySQL 5.5: sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
6) tested the installation: mysql -u root

MySQL Uninstall:
When I tried the second upgrade I had to uninstall MySQL 5.5.  To do this I did the following:

1) delete MySQL install directories: sudo rm -rf /usr/local/mysql
2) delete Mac receipt files: sudo rm -f /private/var/db/receipts/com.mysql*