The original month-to-day suffix for NSDateFormatter setDateFormat

What setDateFormat parameter for NSDateFormatter do I use to get the judgment suffix of the day of the month?

eg. Below is a snapshot below:
15:11 Saturday August 15

What should I change to get:
15:11 Saturday August 15th

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

In PHP, I would use this for the example above:
<?php echo date('h:m A l F jS') ?>

Is there an NSDateFormatter equivalent to the S option in the PHP format string?

+49
iphone cocoa nsdate nsdateformatter
Aug 15 '09 at 22:41
source share
13 answers
 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); 
+54
Aug 16 '09 at 21:41
source share

None of these answers were as pleasant as what I use, so I decided to share with him:




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



Obviously this only works in English.

+71
Apr 24 '14 at 15:45
source share

It is easy to do with 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" 

Taken from 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)!) } 
+20
Jun 24 '15 at 17:59
source share

Here is another implementation for the method for creating the suffix. The suffixes that it produces are valid only in English and may be incorrect in other languages:

 - (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"; } } 
+16
Aug 13 '13 at 22:05
source share

Date formats on Mac OS 10.5 and iPhone use TR35 as the standard format specifier. This specification does not allow such a suffix on any date; if you want it, you will have to generate it yourself.

+7
Aug 16 '09 at 1:12
source share

Matt Andersen's answer is quite complex, as is SDJMcHattie. But NSDateFormatter is pretty heavy on the processor, and if you call it 100x, you really see the effect, so here is the combined solution obtained from the answers above. (Note that the above are still true)

NSDateFormatter is insanely expensive to create. Create it once and repeatedly , but be careful: it is not thread safe, therefore, one per thread.

Assuming 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, this is more convenient than using an array * /

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

Exit: 15:11 Saturday, August 15

+4
Feb 06 '14 at 11:39
source share

This will give a string in the format "10:10 PM on Saturday, August 2"

  -(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; } 
+3
Aug 02 '14 at 9:00 a.m.
source share

Or if you want a suffix for any number:

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

The idea that there are 5 possibilities for positive numbers. This is the first digit of the place: 1 is "st". This is the second place figure - 2, β€œ2nd”. The third digit 3 is "rd". In any other case, it is β€œth”, or if the second-place digit is 1, then these rules do not apply, and this is β€œth”.

Modulo 100 gives us the digit of the last two numbers, so we can check from 11 to 13. Modulo 10 gives us the digit of the last number, so we can check 1, 2, 3 if you don't catch the first condition.

Try this extension on the playgrounds:

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

I would like to see if there is an even shorter way to write this using binary operations and / or an array!

+2
Jun 19 '15 at 17:24
source share
  - (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); } 
+1
Jun 03 '14 at 9:40
source share
 - (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; } 
+1
Nov 17 '14 at 12:54 on
source share

This will lead to formatting in two stages: firstly, create a substring that is the day with the appropriate suffix, then create a format string for the rest of the parts by connecting an already formatted day.

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

Since the ordinal day is built by NumberFormatter , it should work in all languages, not just English.

You can get the format string ordered for the current locale by replacing the assignment with dateFormat as follows:

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

Pay attention to the advice of several others that creating formats is expensive, so you should cache and reuse them in frequently called code.

+1
Jan 04 '17 at 19:42 on
source share

I added these two methods to NSDate with the category NSDate + Add-ons.

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

You could make them more efficient by combining them and specifying one day digit in the format string as the switch point. I decided to separate the functionality, so that serial suffixes can be called separately for different date formats.

0
Oct 03 '14 at 22:45
source share

The NSDateFormatter documentation states that all parameters supported by the format are listed in TR35 .

Why do you need this? If you are doing something for an analysis machine, you should use the ISO 8601 format or the RFC 2822 format if you need to. None of them require or allow an ordinal suffix.

If you display dates for the user, you must use one of the formats from the user locale settings.

-3
Aug 16 '09 at 0:52
source share



All Articles