Ignore:
Timestamp:
08/03/09 08:10:19 (15 years ago)
Author:
Nicholas Riley
Message:

NJRDateFormatter.m: Remove an unused function; actually get ICU-based date formatters working (previously, only Date::Manip was in use); add additional date formatters; resolve issue with "a" and "p" (or localized equivalents) not being interpreted as expected.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Cocoa/Pester/Source/NJRDateFormatter.m

    r367 r577  
    1111#include <dlfcn.h>
    1212
    13 // workaround for bug in Jaguar (and earlier?) NSCalendarDate dateWithNaturalLanguageString:
    14 NSString *stringByRemovingSurroundingWhitespace(NSString *string) {
    15     static NSCharacterSet *nonWhitespace = nil;
    16     NSRange firstValidCharacter, lastValidCharacter;
    17    
    18     if (!nonWhitespace) {
    19         nonWhitespace = [[[NSCharacterSet characterSetWithCharactersInString:
    20                            @" \t\r\n"] invertedSet] retain];
    21     }
    22    
    23     firstValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace];
    24     if (firstValidCharacter.length == 0)
    25         return @"";
    26     lastValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace options: NSBackwardsSearch];
    27    
    28     if (firstValidCharacter.location == 0 && lastValidCharacter.location == [string length] - 1)
    29         return string;
    30     else
    31         return [string substringWithRange: NSUnionRange(firstValidCharacter, lastValidCharacter)];
     13static NSDateFormatter *protoFormatter() {
     14    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
     15    [formatter setLenient: YES];
     16    return formatter;
     17}
     18
     19static NSDateFormatter *dateFormatterWithStyle(NSDateFormatterStyle style) {
     20    NSDateFormatter *formatter = protoFormatter();
     21    [formatter setTimeStyle: NSDateFormatterNoStyle];
     22    [formatter setDateStyle: style];
     23    return formatter;
     24}
     25
     26static NSDateFormatter *timeFormatterWithStyle(NSDateFormatterStyle style) {
     27    NSDateFormatter *formatter = protoFormatter();
     28    [formatter setTimeStyle: style];
     29    [formatter setDateStyle: NSDateFormatterNoStyle];
     30    return formatter;
     31}
     32
     33static NSDateFormatter *timeFormatterWithFormat(NSString *format) {
     34    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
     35    [formatter setDateFormat: format];
     36    [formatter setLenient: NO];
     37    return formatter;
    3238}
    3339
     
    4046};
    4147
     48// note: these formats must be 0-padded where appropriate and contain no spaces
     49// or attempts to force them into strict interpretation will fail
     50static const NSString *timeFormats[] = {
     51    @"hha",
     52    @"HHmmss",
     53    @"HHmm",
     54    @"HH",
     55    nil
     56};
     57
    4258@implementation NJRDateFormatter
    4359
     
    85101    NSMutableArray *tryFormatters = [[NSMutableArray alloc] init];
    86102   
    87     for (const NSDateFormatterStyle *s = formatterStyles ; *s < NSDateFormatterNoStyle ; *s++) {
    88         NSDateFormatter *tryFormatter = [[NSDateFormatter alloc] init];
    89         [tryFormatter setLenient: YES];
    90         [tryFormatter setTimeStyle: NSDateFormatterNoStyle];
    91         [tryFormatter setDateStyle: *s];
     103    for (const NSDateFormatterStyle *s = formatterStyles ; *s != NSDateFormatterNoStyle ; *s++) {
     104        NSDateFormatter *tryFormatter = dateFormatterWithStyle(*s);
    92105        [tryFormatters addObject: tryFormatter];
    93106        [tryFormatter release];
     
    103116    NJRDateFormatter *formatter = [[self alloc] init];
    104117    NSMutableArray *tryFormatters = [[NSMutableArray alloc] init];
    105    
    106     for (const NSDateFormatterStyle *s = formatterStyles ; *s < NSDateFormatterNoStyle ; *s++) {
    107         NSDateFormatter *tryFormatter = [[NSDateFormatter alloc] init];
    108         [tryFormatter setLenient: YES];
    109         [tryFormatter setTimeStyle: *s];
    110         [tryFormatter setDateStyle: NSDateFormatterNoStyle];
     118    NSDateFormatter *tryFormatter;
     119   
     120    for (const NSDateFormatterStyle *s = formatterStyles ; *s != NSDateFormatterNoStyle ; *s++) {
     121        tryFormatter = timeFormatterWithStyle(*s);
     122        [tryFormatters addObject: tryFormatter];
     123        [tryFormatter release];
     124    }
     125    for (NSString **s = timeFormats ; *s != nil ; *s++) {
     126        tryFormatter = timeFormatterWithFormat(*s);
    111127        [tryFormatters addObject: tryFormatter];
    112128        [tryFormatter release];
     
    144160    NSEnumerator *e = [tryFormatters objectEnumerator];
    145161    NSDateFormatter *tryFormatter;
    146    
    147     // XXX untested; does this work?
     162    NSString *cleaned = nil;
     163
     164    // don't let time specifications ending in "a" or "p" trigger Date::Manip
     165    if ([self timeStyle] != NSDateFormatterNoStyle &&
     166        [string length] > 1 &&
     167        ![[NSCharacterSet letterCharacterSet]
     168           characterIsMember: [string characterAtIndex: [string length] - 2]]) {
     169
     170        NSString *am = [self AMSymbol], *pm = [self PMSymbol];
     171        if (am != nil && [am length] > 1 && pm != nil && [pm length] > 1) {
     172
     173            NSString *a = [am substringToIndex: 1], *p = [pm substringToIndex: 1];
     174            if (![a isCaseInsensitiveLike: p]) {
     175
     176                NSString *last = [string substringFromIndex: [string length] - 1];
     177                if ([last isCaseInsensitiveLike: a])
     178                    string = [string stringByAppendingString: [am substringFromIndex: 1]];
     179                if ([last isCaseInsensitiveLike: p])
     180                    string = [string stringByAppendingString: [pm substringFromIndex: 1]];
     181            }
     182        }
     183    }
     184   
    148185    while ( (tryFormatter = [e nextObject]) != nil) {
    149186        date = [tryFormatter dateFromString: string];
    150         if (date != nil) goto success;
    151     }
    152    
    153     if (parse_natural_language_date == NULL) return nil;
     187
     188        if (date == nil)
     189            continue;
     190
     191        if (([tryFormatter dateStyle] != NSDateFormatterNoStyle) ||
     192            ([tryFormatter timeStyle] != NSDateFormatterNoStyle))
     193            goto success;
     194
     195        // XXX ICU-based "format" formatters return 0 instead of nil
     196        if ([date timeIntervalSince1970] == 0)
     197            continue;
     198
     199        // even non-lenient ICU-based "format" formatters are insufficiently strict,
     200        // permitting arbitrary characters before and after the parsed string
     201        NSString *formatted = [tryFormatter stringFromDate: date];
     202        if (cleaned == nil)
     203            cleaned = [[string componentsSeparatedByString: @" "] componentsJoinedByString: @""];
     204        if ([cleaned characterAtIndex: 0] != '0' && [formatted characterAtIndex: 0] == '0')
     205            formatted = [formatted substringFromIndex: 1];
     206
     207        if ([formatted isCaseInsensitiveLike: cleaned])
     208            goto success;
     209    }
     210   
     211    if (parse_natural_language_date == NULL) return NO;
    154212
    155213    date = parse_natural_language_date(string);
Note: See TracChangeset for help on using the changeset viewer.