NSDateFormatter setDateFormat的序数月 - 日后缀选项

时间:2009-08-15 22:41:42

标签: iphone cocoa nsdate nsdateformatter

我使用什么setDateFormat选项获取NSDateFormatter以获取月日序数后缀?

e.g。目前下面的片段产生:
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格式化字符串中的 S 选项?

16 个答案:

答案 0 :(得分:89)

这些答案中没有一个像我使用的那样美观,所以我想我会分享:


斯威夫特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"
    }
}

目标-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";
    }
}

显然,这只适用于英语。

答案 1 :(得分:54)

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);

答案 2 :(得分:26)

从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)!)
}

答案 3 :(得分:16)

这是生成后缀的方法的另一种实现。它产生的后缀仅在英语中有效,在其他语言中可能不正确:

- (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";
    }
}

答案 4 :(得分:9)

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

答案 5 :(得分:4)

Matt Andersen的回答非常详细,SDJMcHattie也是如此。但是NSDateFormatter在cpu上相当沉重,如果你称之为100x,你真的看到了影响,所以这里是一个从上面的答案中得出的综合解决方案。 (请注意,上述内容仍然正确)

NSDateFormatter疯狂地昂贵来创建。创建一次重用,但要注意:它不是线程安全的,因此每个线程一个。

假设 self.date = [NSDate date];

   - (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

答案 6 :(得分:3)

这将以“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;
    }

答案 7 :(得分:3)

这将分两步进行格式化:首先,创建一个具有适当后缀的日子字符串,然后为剩余部分创建一个格式字符串,插入已经格式化的日期。

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构建,因此它应该适用于所有语言,而不仅仅是英语。

您可以通过将作业替换为dateFormat来获取为当前区域设置排序的格式字符串:

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

请注意其他几个人建议格式化程序的建议很昂贵,因此您应该在经常调用的代码中缓存和重用它们。

答案 8 :(得分:2)

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

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是“第二”。这是第三名数字是3是“rd”。任何其他情况为“th”,或者如果它的第二位数字为1,则上述规则不适用且为“th”。

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

在游乐场尝试扩展:

let a = -1 

a.suffix() // "st"

let b = 1112 

b.suffix() // "th"

let c = 32 

c.suffix() // "nd"

很想看看是否有更短的方法来使用二进制操作和/或数组来编写它!

答案 9 :(得分:2)

这已在基金会中实现。

let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .ordinal
numberFormatter.locale = Locale.current

numberFormatter.string(for: 1) //Should produce 1st
numberFormatter.string(for: 2) //Should produce 2nd
numberFormatter.string(for: 3) //Should produce 3rd
numberFormatter.string(for: 4) //Should produce 4th

答案 10 :(得分:1)

   - (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);

}

答案 11 :(得分:1)

没有一个答案使用swift中数字格式化程序中已经存在的序数字样式。

    var dateString: String {
       let calendar = Calendar.current
       let dateComponents = calendar.component(.day, from: date)
       let numberFormatter = NumberFormatter()
       numberFormatter.numberStyle = .ordinal
       let day = numberFormatter.string(from: dateComponents as NSNumber)
       let dateFormatter = DateFormatter()
       dateFormatter.dateFormat = "MMM"
       return day! + dateFormatter.string(from: date)
    }

答案 12 :(得分:0)

我将这两种方法添加到NSDate中,类别为NSDate + Additions。

\- (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;
}

通过组合它们并将格式字符串中当天的位数作为切换点,可以使它们更有效率。我选择分离功能,因此可以针对不同的日期格式单独调用序数后缀。

答案 13 :(得分:0)

- (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;
}

答案 14 :(得分:0)

我只是使用了这里的一些答案来自己解决这个问题,但我认为我的解决方案与这里的一些解决方案略有不同。

我喜欢使用 NumberFormatter 来正确处理序数格式(使用本地化),并使用 DateFormatter 来处理其余的问题,但我不喜欢这些解决方案中的一些需要在每次使用时重新构建日期格式化程序(这很昂贵)。

这是我正在使用的,它应该通过依赖 Apple 的 API 的方式提供体面的本地化,并且由于格式化程序的静态创建(需要 iOS 9.0+),不应该过多地处理:

>
// ...in a class that needs ordinal date formatting

static let stringFormatDateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    // A date format, replacing `d` with `'%@'` string format placeholder
    formatter.dateFormat = "MMM '%@', YYYY" 
    return formatter
}()

static let ordinalFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    formatter.numberStyle = .ordinal
    return formatter
}()

func ordinalDateString(from date: Date) -> String {

    // Pull the day from the date
    let day = NSCalendar.current.component(.day, from: date)

    // Create the ordinal, fall back to non-ordinal number due to optionality
    let dayOrdinal = Self.ordinalFormatter.string(for: day) ?? "\(day)"

    // Create the formatter with placeholder for day (e.g. "Jan %@, 2011")
    let dateStringFormat = Self.stringFormatDateFormatter.string(from: date)

    // Inject ordinal ("Jan 10th, 2011")
    return String(format: dateStringFormat, dayOrdinal)
}

答案 15 :(得分:-3)

NSDateFormatter文档说它支持的所有格式选项都是listed in TR35

你为什么要这个?如果您要为要解析的计算机制作内容,则应使用ISO 8601 formatRFC 2822 format(如果必须)。其中任何一个都不需要或允许有序后缀。

如果您要向用户显示日期,则应使用用户区域设置中的一种格式。