Is there an easy way in .NET to get "st", "nd", "rd" and "th" endings for numbers?

.NetFormattingDateOrdinals

.Net Problem Overview


I am wondering if there is a method or format string I'm missing in .NET to convert the following:

   1 to 1st
   2 to 2nd
   3 to 3rd
   4 to 4th
  11 to 11th
 101 to 101st
 111 to 111th

This link has a bad example of the basic principle involved in writing your own function, but I am more curious if there is an inbuilt capacity I'm missing.

Solution

Scott Hanselman's answer is the accepted one because it answers the question directly.

For a solution however, see this great answer.

.Net Solutions


Solution 1 - .Net

It's a function which is a lot simpler than you think. Though there might be a .NET function already in existence for this, the following function (written in PHP) does the job. It shouldn't be too hard to port it over.

function ordinal($num) {
    $ones = $num % 10;
    $tens = floor($num / 10) % 10;
    if ($tens == 1) {
        $suff = "th";
    } else {
        switch ($ones) {
            case 1 : $suff = "st"; break;
            case 2 : $suff = "nd"; break;
            case 3 : $suff = "rd"; break;
            default : $suff = "th";
        }
    }
    return $num . $suff;
}

Solution 2 - .Net

Simple, clean, quick

    private static string GetOrdinalSuffix(int num)
    {
        string number = num.ToString();
        if (number.EndsWith("11")) return "th";
        if (number.EndsWith("12")) return "th";
        if (number.EndsWith("13")) return "th";
        if (number.EndsWith("1")) return "st";
        if (number.EndsWith("2")) return "nd";
        if (number.EndsWith("3")) return "rd";
        return "th";
    }

Or better yet, as an extension method

public static class IntegerExtensions
{
    public static string DisplayWithSuffix(this int num)
    {
        string number = num.ToString();
        if (number.EndsWith("11")) return number + "th";
        if (number.EndsWith("12")) return number + "th";
        if (number.EndsWith("13")) return number + "th";
        if (number.EndsWith("1")) return number + "st";
        if (number.EndsWith("2")) return number + "nd";
        if (number.EndsWith("3")) return number + "rd";
        return number + "th";
    }
}

Now you can just call

int a = 1;
a.DisplayWithSuffix(); 

or even as direct as

1.DisplayWithSuffix();

Solution 3 - .Net

No, there is no inbuilt capability in the .NET Base Class Library.

Solution 4 - .Net

@nickf: Here is the PHP function in C#:

public static string Ordinal(int number)
{
	string suffix = String.Empty;
	
	int ones = number % 10;
	int tens = (int)Math.Floor(number / 10M) % 10;
	
	if (tens == 1)
	{
		suffix = "th";
	}
	else
	{
		switch (ones)
		{
			case 1:
				suffix = "st";
				break;
				
			case 2:
				suffix = "nd";
				break;
				
			case 3:
				suffix = "rd";
				break;
				
			default:
				suffix = "th";
				break;
		}
	}
	return String.Format("{0}{1}", number, suffix);
}

Solution 5 - .Net

This has already been covered but I'm unsure how to link to it. Here is the code snippit:

	public static string Ordinal(this int number)
	{
		var ones = number % 10;
		var tens = Math.Floor (number / 10f) % 10;
		if (tens == 1)
		{
			return number + "th";
		}

		switch (ones)
		{
			case 1: return number + "st";
			case 2: return number + "nd";
			case 3: return number + "rd";
			default: return number + "th";
		}
	}

FYI: This is as an extension method. If your .NET version is less than 3.5 just remove the this keyword

[EDIT]: Thanks for pointing that it was incorrect, that's what you get for copy / pasting code :)

Solution 6 - .Net

Here's a Microsoft SQL Server Function version:

CREATE FUNCTION [Internal].[GetNumberAsOrdinalString]
(
    @num int
)
RETURNS nvarchar(max)
AS
BEGIN

    DECLARE @Suffix nvarchar(2);
    DECLARE @Ones int;  
    DECLARE @Tens int;
    
    SET @Ones = @num % 10;
    SET @Tens = FLOOR(@num / 10) % 10;

    IF @Tens = 1
    BEGIN
        SET @Suffix = 'th';
    END
    ELSE
    BEGIN

    SET @Suffix = 
        CASE @Ones
            WHEN 1 THEN 'st'
            WHEN 2 THEN 'nd'
            WHEN 3 THEN 'rd'
            ELSE 'th'
        END
    END

    RETURN CONVERT(nvarchar(max), @num) + @Suffix;
END

Solution 7 - .Net

I know this isn't an answer to the OP's question, but because I found it useful to lift the SQL Server function from this thread, here is a Delphi (Pascal) equivalent:

function OrdinalNumberSuffix(const ANumber: integer): string;
begin
  Result := IntToStr(ANumber);
  if(((Abs(ANumber) div 10) mod 10) = 1) then // Tens = 1
    Result := Result + 'th'
  else
    case(Abs(ANumber) mod 10) of
      1: Result := Result + 'st';
      2: Result := Result + 'nd';
      3: Result := Result + 'rd';
      else
        Result := Result + 'th';
    end;
end;

Does ..., -1st, 0th make sense?

Solution 8 - .Net

Another flavor:

/// <summary>
/// Extension methods for numbers
/// </summary>
public static class NumericExtensions
{
	/// <summary>
	/// Adds the ordinal indicator to an integer
	/// </summary>
	/// <param name="number">The number</param>
	/// <returns>The formatted number</returns>
	public static string ToOrdinalString(this int number)
	{
		// Numbers in the teens always end with "th"

		if((number % 100 > 10 && number % 100 < 20))
			return number + "th";
		else
		{
			// Check remainder

			switch(number % 10)
			{
				case 1:
					return number + "st";

				case 2:
					return number + "nd";

				case 3:
					return number + "rd";

				default:
					return number + "th";
			}
		}
	}
}

Solution 9 - .Net

public static string OrdinalSuffix(int ordinal)
{
    //Because negatives won't work with modular division as expected:
	var abs = Math.Abs(ordinal); 
		
	var lastdigit = abs % 10; 

	return 
        //Catch 60% of cases (to infinity) in the first conditional:
        lastdigit > 3 || lastdigit == 0 || (abs % 100) - lastdigit == 10 ? "th" 
            : lastdigit == 1 ? "st" 
            : lastdigit == 2 ? "nd" 
            : "rd";
}

Solution 10 - .Net

else if (choice=='q')
{
    qtr++;
                  
    switch (qtr)
    {
        case(2): strcpy(qtrs,"nd");break;
        case(3):
        {
           strcpy(qtrs,"rd");
           cout<<"End of First Half!!!";
           cout<<" hteam "<<"["<<hteam<<"] "<<hs;
           cout<<" vteam "<<" ["<<vteam;
           cout<<"] ";
           cout<<vs;dwn=1;yd=10;
                      
           if (beginp=='H') team='V';
           else             team='H';
           break;
       }
       case(4): strcpy(qtrs,"th");break;

Solution 11 - .Net

I think the ordinal suffix is hard to get... you basically have to write a function that uses a switch to test the numbers and add the suffix.

There's no reason for a language to provide this internally, especially when it's locale specific.

You can do a bit better than that link when it comes to the amount of code to write, but you have to code a function for this...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt MitchellView Question on Stackoverflow
Solution 1 - .NetnickfView Answer on Stackoverflow
Solution 2 - .NetShahzad QureshiView Answer on Stackoverflow
Solution 3 - .NetScott HanselmanView Answer on Stackoverflow
Solution 4 - .NetScott DormanView Answer on Stackoverflow
Solution 5 - .NetmjalldayView Answer on Stackoverflow
Solution 6 - .NetredcalxView Answer on Stackoverflow
Solution 7 - .NetavenmoreView Answer on Stackoverflow
Solution 8 - .NetFrank HoffmanView Answer on Stackoverflow
Solution 9 - .NetFaustView Answer on Stackoverflow
Solution 10 - .Net From GusView Answer on Stackoverflow
Solution 11 - .NetHugh BuchananView Answer on Stackoverflow