Is there a way to use NSNumberFormatter to get the \'th\' \'st\' \'nd\' \'rd\' number endings?
EDIT:
Looks like it does not exist. Here\'s what I\'m using.
Here's a Swift solution that cycles through the user's preferred languages until it finds one with known rules (which are pretty easy to add) for ordinal numbers:
extension Int {
var localizedOrdinal: String {
func ordinalSuffix(int: Int) -> String {
for language in NSLocale.preferredLanguages() as [String] {
switch language {
case let l where l.hasPrefix("it"):
return "°"
case let l where l.hasPrefix("en"):
switch int {
case let x where x != 11 && x % 10 == 1:
return "st"
case let x where x != 12 && x % 10 == 2:
return "nd"
case let x where x != 13 && x % 10 == 3:
return "rd"
default:
return "th"
}
default:
break
}
}
return ""
}
return "\(self)" + ordinalSuffix(self)
}
}
This was my brute force implementation to taking a NSString* representation of the date and returning the ordinal value. I feel it's much easier to read.
NSDictionary *ordinalDates = @{
@"1": @"1st",
@"2": @"2nd",
@"3": @"3rd",
@"4": @"4th",
@"5": @"5th",
@"6": @"6th",
@"7": @"7th",
@"8": @"8th",
@"9": @"9th",
@"10": @"10th",
@"11": @"11th",
@"12": @"12th",
@"13": @"13th",
@"14": @"14th",
@"15": @"15th",
@"16": @"16th",
@"17": @"17th",
@"18": @"18th",
@"19": @"19th",
@"20": @"20th",
@"21": @"21st",
@"22": @"22nd",
@"23": @"23rd",
@"24": @"24th",
@"25": @"25th",
@"26": @"26th",
@"27": @"27th",
@"28": @"28th",
@"29": @"29th",
@"30": @"30th",
@"31": @"31st" };
You can try this, Its well simplified.
function numberToOrdinal(n) {
if (n==0) {
return n;
}
var j = n % 10,
k = n % 100;
if (j == 1 && k != 11) {
return n + "st";
}
if (j == 2 && k != 12) {
return n + "nd";
}
if (j == 3 && k != 13) {
return n + "rd";
}
return n + "th";
}
Here's a compact Swift extension suitable for all integer types:
extension IntegerType {
func ordinalString() -> String {
switch self % 10 {
case 1...3 where 11...13 ~= self % 100: return "\(self)" + "th"
case 1: return "\(self)" + "st"
case 2: return "\(self)" + "nd"
case 3: return "\(self)" + "rd"
default: return "\(self)" + "th"
}
}
}
Example usage:
let numbers = (0...30).map { $0.ordinalString() }
print(numbers.joinWithSeparator(", "))
Output:
0th, 1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th, 20th, 21st, 22nd, 23rd, 24th, 25th, 26th, 27th, 28th, 29th, 30th
Here's a short Int extension for the English language that also accounts for and displays negative integers correctly:
extension Int {
func ordinal() -> String {
let suffix: String!
// treat negative numbers as positive for suffix
let number = (self < 0 ? self * -1 : self)
switch number % 10 {
case 0:
suffix = self != 0 ? "th" : ""
case 1:
suffix = "st"
case 2:
suffix = "nd"
case 3:
suffix = "rd"
default:
suffix = "th"
}
return String(self) + suffix
}
}
The correct way to do this from iOS 9 onwards, is:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterOrdinalStyle;
NSLog(@"%@", [numberFormatter stringFromNumber:@(1)]); // 1st
NSLog(@"%@", [numberFormatter stringFromNumber:@(2)]); // 2nd
NSLog(@"%@", [numberFormatter stringFromNumber:@(3)]); // 3rd, etc.
Alternatively:
NSLog(@"%@", [NSString localizedStringFromNumber:@(1)
numberStyle:NSNumberFormatterOrdinalStyle]); // 1st