Using the new NSDateFormatter

As of Tiger, a new NSDateFormatter has been introduced to Foundation, and within it are a few things that might take some getting used to. So I will outline the date formatter in its entirety, and how to understand how all of the pieces work together.There are two main modes, or behaviors, of the NSDateFormatter: Pre 10.4 and 10.4+ (these same labels are used in Interface Builder).

  • Pre 10.4 Mode (NSDateFormatterBehavior10_0)
    This mode was the only mode until Tiger was introduced, and it makes use of the the strftime-style format strings. The strftime format identifiers look like “%S” (seconds), “%m” (month number), and “%d” (day of month) to just name a few. Actually, the documentation for these identifiers is accurately described in Apple’s documentation that comes with Xcode or is found online at the ADC website.

    UsageSo how might I go about creating a date formatter that exhibits the old Pre 10.4 behavior? Well, it’s actually quite simple. When you create your instance of NSDateFormatter, use the initWithDateFormat:allowNaturalLanguage: initializer, instead of the usual init method.You should note:Once you create the Pre 10.4 date formatter with a format string, you cannot change it. Though NSDateFormatter has a method setDateFormat:, it only applies to the new date formatter behavior. You can however, convert the date formatter to the newer behavior by calling setDateFormatterBehavior: and passing in NSDateFormatterBehavior10_4.

    Sample code

        NSDateFormatter *df = [[[NSDateFormatter alloc] initWithDateFormat:@"%1m/%1d/%y"
                                                        allowNaturalLanguage:YES]
                                                        autorelease];
        // The following code will print something like 2/11/2007. Also notice how
        // putting the '1' before the 'm' and 'd' in our format string took the padding
        // zeros away.
        NSLog(@"%@", [df stringForObjectValue:[NSDate date]]);
    
  • 10.4+ Mode NSDateFormatterBehavior10_4
    Arguably the behavior you will want to use in your code is the 10.4+ Mode. This mode conforms to the Unicode TR35-4 standard, so it has a ton of features that the Pre 10.4 behavior just doesn’t have. For one, it uses different identifiers, the Unicode site at this link has all of the identifiers and how you can use them to construct date format strings. The documentation is mostly accurate except that though ICU claims three lower case e’s (”eee”) should evaluate to something like “Tues” or “Wed”, that isn’t reflected by the NSDateFormatter.

    Changing the date format string
    One of the really nice things about the new date formatter behavior is that you can set the date format string to something else after you create it. If you call setDateFormat: with some string, the changes are made immediately. This is nice if your date format string is dynamic.

    Date and Time Styles
    Another feature of the 10.4+ behavior is that you can tell it to ignore date format strings all together, and instead use the time styles defined by the user in System Preferences. These are set by each user on their own system in the International pane of System Preferences:

    You can set a date or time style such as short, medium, long, full, or none at all. The methods for doing this are setDateStyle: and setTimeStyle:. The tricky part about using these styles programmatically comes in the order that you call those methods. For example, if you call setDateStyle: or setTimeStyle:, it voids the effect of the date format string. However, if after calling setDateStyle: or setTimeStyle:, you set the date format string by calling setDateFormat:, it then voids the time and date styles you just applied. The general rule of thumb is that whatever you call last is what the date formatter uses. If you set the date or time style last, it uses that; if you set the date format string last, then it uses that. The code below illustrates these little quirks.

        // Create our date formatter and a sample date to work with
        NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
        NSDate *date = [NSDate date];
    
        // This will produce a date such as "07/11/2007 22:15".
        [formatter setDateStyle:NSDateFormatterShortStyle];
        [formatter setTimeStyle:NSDateFormatterShortStyle];
        NSLog(@"%@", [formatter stringFromDate:date]);
    
        // This will produce a date such as "07/11/2007", notice, without the time.
        [formatter setTimeStyle:NSDateFormatterNoStyle];
        NSLog(@"%@", [formatter stringFromDate:date]);
    
        // This will produce a date such as "7 Nov 2007", thus nullifying the date
        // and time styles we set above.
        [formatter setDateFormat:@"d MMM yyyy"];
        NSLog(@"%@", [formatter stringFromDate:date]);
    
        // But now if I reset the date style, we nullify our date format string.
        // And though I didn't reset the time style, since I reset the date style,
        // the formatter assumes the use of both.
        [formatter setDateStyle:NSDateFormatterShortStyle];
        NSLog(@"%@", [formatter stringFromDate:date]);
    

The NSDateFormatter can be a tricky or intimidating class at first, but I think when you really unpack it, it is quite easy. Just remember:

  • Two modes: pre 10.4 (strftime-style, NSDateFormatterBehavior10_0) and 10.4+ (Unicode, NSDateFormatterBehavior10_4).
  • When using pre 10.4 behavior, use initWithDateFormat:allowNaturalLanguage: to create it. And remember, once you create it, you can’t change the format string.
  • When using 10.4+ behavior, uses standard init to create it. You can use a date format string or the date/time styles. And when setting these, remember that the last method you call is the style it uses (date format string versus date/time styles).
  • Check out the Apple and Unicode documentation for a complete list of identifiers.

Leave a Reply

You must login to post a comment.