NSDateFormatter setDateFormat的序号月份后缀选项

什么setDateFormat选项NSDateFormatter我用来获得一个月份的序号后缀?

例如下面的代码片段产生:
8月15日星期六下午3:11

我必须改变什么来获得:
8月15 星期六下午3:11

NSDate *date = [NSDate date]; NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [dateFormatter setDateFormat:@"h:mm a EEEE MMMM d"]; NSString *dateString = [dateFormatter stringFromDate:date]; NSLog(@"%@", dateString); 

在PHP中,我会用上面的情况:
<?php echo date('h:m A l F jS') ?>

是否有一个NSDateFormatter相当于PHP格式string中的S选项?

这些答案都不像我使用的那样美观,所以我想我会分享:


Swift 3:

 func daySuffix(from date: Date) -> String { let calendar = Calendar.current let dayOfMonth = calendar.component(.day, from: date) switch dayOfMonth { case 1, 21, 31: return "st" case 2, 22: return "nd" case 3, 23: return "rd" default: return "th" } } 

Objective-C的:

 - (NSString *)daySuffixForDate:(NSDate *)date { NSCalendar *calendar = [NSCalendar currentCalendar]; NSInteger dayOfMonth = [calendar component:NSCalendarUnitDay fromDate:date]; switch (dayOfMonth) { case 1: case 21: case 31: return @"st"; case 2: case 22: return @"nd"; case 3: case 23: return @"rd"; default: return @"th"; } } 

显然,这只适用于英语。

 NSDate *date = [NSDate date]; NSDateFormatter *prefixDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [prefixDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [prefixDateFormatter setDateFormat:@"h:mm a EEEE MMMM d"]; NSString *prefixDateString = [prefixDateFormatter stringFromDate:date]; NSDateFormatter *monthDayFormatter = [[[NSDateFormatter alloc] init] autorelease]; [monthDayFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [monthDayFormatter setDateFormat:@"d"]; int date_day = [[monthDayFormatter stringFromDate:date] intValue]; NSString *suffix_string = @"|st|nd|rd|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|st|nd|rd|th|th|th|th|th|th|th|st"; NSArray *suffixes = [suffix_string componentsSeparatedByString: @"|"]; NSString *suffix = [suffixes objectAtIndex:date_day]; NSString *dateString = [prefixDateString stringByAppendingString:suffix]; NSLog(@"%@", dateString); 

这很容易做到iOS9

 NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; formatter.numberStyle = NSNumberFormatterOrdinalStyle; NSArray<NSNumber *> *numbers = @[@1, @2, @3, @4, @5]; for (NSNumber *number in numbers) { NSLog(@"%@", [formatter stringFromNumber:number]); } // "1st", "2nd", "3rd", "4th", "5th" 

采取从NSHipster

Swift 2.2:

 let numberFormatter = NSNumberFormatter() numberFormatter.numberStyle = .OrdinalStyle let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] for number in numbers { print(numberFormatter.stringFromNumber(number)!) } 

下面是另一个生成后缀的方法的实现。 它产生的后缀只在英文中有效,在其他语言中可能不正确:

 - (NSString *)suffixForDayInDate:(NSDate *)date { NSInteger day = [[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] components:NSDayCalendarUnit fromDate:date] day]; if (day >= 11 && day <= 13) { return @"th"; } else if (day % 10 == 1) { return @"st"; } else if (day % 10 == 2) { return @"nd"; } else if (day % 10 == 3) { return @"rd"; } else { return @"th"; } } 

Mac OS 10.5和iPhone上的date格式化程序使用TR35作为格式说明符标准。 这个规范不允许在任何date有这样的后缀; 如果你想要一个,你必须自己生成它。

马特·安德森的回答相当详细,SDJMcHattie也是如此。 但NSDateFormatter在cpu上相当沉重,如果你把这个叫做100x,你真的看到了这个影响,所以这里是从上面的答案中得到的一个综合的解决scheme。 (请注意以上依然是正确的)

NSDateFormatter创build起来非常昂贵 。 创build一次 并重用 ,但要小心:它不是线程安全的,所以每个线程一个。

假设self.date = [NSDatedate];

  - (NSString *)formattedDate{ static NSDateFormatter *_dateFormatter = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _dateFormatter = [[NSDateFormatter alloc] init]; _dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; _dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; }); _dateFormatter.dateFormat = [NSString stringWithFormat:@"h:mm a EEEE MMMM d'%@'", [self suffixForDayInDate:self.date]]; NSString *date = [_dateFormatter stringFromDate:self.date]; return date; } 

/ * SDJMcHattie的代码,这比使用数组更方便* /

 - (NSString *)suffixForDayInDate:(NSDate *)date{ NSInteger day = [[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] components:NSDayCalendarUnit fromDate:date] day]; if (day >= 11 && day <= 13) { return @"th"; } else if (day % 10 == 1) { return @"st"; } else if (day % 10 == 2) { return @"nd"; } else if (day % 10 == 3) { return @"rd"; } else { return @"th"; } } 

产出:8月15日星期六下午3:11

这将给出格式“8月2日星期六下午10:10”

  -(NSString*) getTimeInString:(NSDate*)date { NSString* string=@""; NSDateComponents *components = [[NSCalendar currentCalendar] components: NSCalendarUnitDay fromDate:date]; if(components.day == 1 || components.day == 21 || components.day == 31){ string = @"st"; }else if (components.day == 2 || components.day == 22){ string = @"nd"; }else if (components.day == 3 || components.day == 23){ string = @"rd"; }else{ string = @"th"; } NSDateFormatter *prefixDateFormatter = [[NSDateFormatter alloc] init]; [prefixDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [prefixDateFormatter setDateFormat:[NSString stringWithFormat:@"h:mm a EEEE, d'%@' MMMM",string]]; NSString *dateString = [prefixDateFormatter stringFromDate:date]; return dateString; } 

或者如果你想要任何数字的后缀:

 extension Int { public func suffix() -> String { let absSelf = abs(self) switch (absSelf % 100) { case 11...13: return "th" default: switch (absSelf % 10) { case 1: return "st" case 2: return "nd" case 3: return "rd" default: return "th" } } } } 

这个想法是有正数的5个可能性。 这是第一名数字是1是“st”。 第二名数字是2是“2nd”。 第三名数字是3“rd”。 其他情况是“th”,如果是第二位数字是1,则上述规则不适用,并且是“th”。

模100给我们的数字的最后两个数字,所以我们可以检查11到13.模10给我们的数字的最后一个数字,所以我们可以检查1,2,3,如果没有被第一个条件捕获。

在游乐场试试这个扩展:

 let a = -1 a.suffix() // "st" let b = 1112 b.suffix() // "th" let c = 32 c.suffix() // "nd" 

想看看是否有更简单的方法来写这个使用二进制操作和/或数组!

  - (void)viewDidLoad { NSDate *date = [NSDate date]; NSDateFormatter *prefixDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [prefixDateFormatter setDateFormat:@"yyy-dd-MM"]; date = [prefixDateFormatter dateFromString:@"2014-6-03"]; //enter yourdate [prefixDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [prefixDateFormatter setDateFormat:@"EEEE MMMM d"]; NSString *prefixDateString = [prefixDateFormatter stringFromDate:date]; NSDateFormatter *monthDayFormatter = [[[NSDateFormatter alloc] init] autorelease]; [monthDayFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [monthDayFormatter setDateFormat:@"d"]; int date_day = [[monthDayFormatter stringFromDate:date] intValue]; NSString *suffix_string = @"|st|nd|rd|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|st|nd|rd|th|th|th|th|th|th|th|st"; NSArray *suffixes = [suffix_string componentsSeparatedByString: @"|"]; NSString *suffix = [suffixes objectAtIndex:date_day]; NSString *dateString = [prefixDateString stringByAppendingString:suffix]; NSLog(@"%@", dateString); } 
 - (NSString *)dayWithSuffixForDate:(NSDate *)date { NSInteger day = [[[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:date] day]; NSString *dayOfMonthWithSuffix, *suffix = nil ; if(day>0 && day <=31) { switch (day) { case 1: case 21: case 31: suffix = @"st"; break; case 2: case 22: suffix = @"nd"; break; case 3: case 23: suffix = @"rd"; break; default: suffix = @"th"; break; } dayOfMonthWithSuffix = [NSString stringWithFormat:@"%ld%@", (long)day , suffix]; } return dayOfMonthWithSuffix; } 

这将分两步进行格式化:首先,创build一个具有适当后缀的date的子string,然后为其余部分创build一个格式string,插入已格式化的date。

 func ordinalDate(date: Date) -> String { let ordinalFormatter = NumberFormatter() ordinalFormatter.numberStyle = .ordinal let day = Calendar.current.component(.day, from: date) let dayOrdinal = ordinalFormatter.string(from: NSNumber(value: day))! let dateFormatter = DateFormatter() dateFormatter.dateFormat = "h:mm a EEEE MMMM '\(dayOrdinal)'" return dateFormatter.string(from: Date()) } 

由于NumberFormatter创build序号date,它应该在所有语言,而不仅仅是英语。

您可以通过用以下代码将dateFormatreplace为当前语言环境来获取格式string:

 dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "h:mm a EEEE MMMM d", options: 0, locale: dateFormatter.locale)?.replacingOccurrences(of: "d", with: "'\(dayOrdinal)'") 

请注意其他人的build议,即创build格式化程序的代价很高,因此您应该在频繁调用的代码中caching和重用它们。

我用NSDate + Additions类将这两个方法添加到NSDate中。

 \- (NSString *)monthDayYear { NSDateFormatter * dateFormatter = NSDateFormatter.new; [dateFormatter setDateFormat:@"MMMM d*, YYYY"]; NSString *dateString = [dateFormatter stringFromDate:self]; return [dateString stringByReplacingOccurrencesOfString:@"*" withString:[self ordinalSuffixForDay]]; } \- (NSString *)ordinalSuffixForDay { NSDateFormatter * dateFormatter = NSDateFormatter.new; [dateFormatter setDateFormat:@"d"]; NSString *dateString = [dateFormatter stringFromDate:self]; NSString *suffix = @"th"; if ([dateString length] == 2 && [dateString characterAtIndex:0] == '1') { return suffix; } switch ([dateString characterAtIndex:[dateString length]-1]) { case '1': suffix = @"st"; break; case '2': suffix = @"nd"; break; case '3': suffix = @"rd"; break; } return suffix; } 

您可以通过组合它们并将格式string中当天的位置数字作为切换点索引来提高效率。 我select分开function,因此可以针对不同的date格式分别调用序号后缀。

NSDateFormatter文档说,它支持的所有格式选项在TR35中列出 。

你为什么要这个? 如果你正在为parsing某个机器做些什​​么,那么你必须使用ISO 8601格式或RFC 2822格式 。 这些都不需要或允许序号后缀。

如果您向用户显示date,则应使用用户区域设置中的某种格式。