有没有一种简单的方法可以在C#中创建序数?


202

C#中有没有一种简单的方法可以为数字创建数?例如:

  • 1返回第一
  • 2返回第二
  • 3返回第三
  • ...等等

可以通过完成此操作String.Format()还是可以使用任何功能?

Answers:


310

该页面为您提供了所有自定义数字格式设置规则的完整列表:

http://msdn.microsoft.com/zh-CN/library/0c899ak8.aspx

如您所见,关于序号的内容不多,因此无法使用String.Format来完成。然而,编写一个函数来实现它并不难。

public static string AddOrdinal(int num)
{
    if( num <= 0 ) return num.ToString();

    switch(num % 100)
    {
        case 11:
        case 12:
        case 13:
            return num + "th";
    }

    switch(num % 10)
    {
        case 1:
            return num + "st";
        case 2:
            return num + "nd";
        case 3:
            return num + "rd";
        default:
            return num + "th";
    }
}

更新:从技术上讲,对于<= 0而言,普通字符不存在,因此我更新了上面的代码。还删除了多余的ToString()方法。

另请注意,这不是国际化的。我不知道其他语言的序号是什么样。


2
Assert.AreEqual(“ 0”,AddOrdinal(0)); 参见wisegeek.com/what-is-an-ordinal-number.htm
si618,2009年

2
在这里,使用扩展方法(或任何称为它的方法-参见@Stu的答案)将非常有用。@Si,如果需要的话,添加该条件将非常容易。
斯特拉格2009年

12
忘记了“ 11th,12th 13th” ...应该是面试问题。:-)
Holf 2012年

2
是的,程序员很好;)
萨姆森(Samjudson

2
@IanWarburton没有冗余,因为将仅命中单个return语句。如果您对答案不满意,请提供您自己的答案,并向我们展示“正确”的方法,以及这样做的重要性。
B2K

73

记住国际化!

这里的解决方案仅适用于英语。如果您需要支持其他语言,事情会变得复杂得多。

例如,在西班牙语中,“ 1st”将被写为“ 1.o”,“ 1.a”,“ 1.os”或“ 1.as”,具体取决于您要计数的是男性,女性还是复数形式!

因此,如果您的软件需要支持其他语言,请尝试避免使用普通字符。


7
@ Andomar:意大利语中的“前2位读者” =>(我想也是西班牙语)在这里“ first”是复数形式。因此,您拥有单数男性,单数女性,复数男性,复数女性;也许某些语言也具有中性的情况(与人/动物区分开)
M.Turrini

2
就是说,您不必避免使用普通字词:只要您知道可能遇到的所有情况或(使您的客户)接受某些限制,就可以将它们包括在本地化中。
M.Turrini 2009年

26
这就解释了为什么.NET团队避免将其添加到DateTime格式化程序中的原因
Chris S 2010年

moment.js具有按地区设置的“常规”格式设置功能,因此它似乎可行,也希望他们可以在.NET中为DateTime完成它
Guillaume86

5
如果都使用“。”,那将非常简单。普通字符,就像我们在德语中一样))))1. 2. 3. 4. 5.等语法案例包含3种不同的文章,此外还有12种不同组合的单数和复数案例。想到这一点,我想俄罗斯人不会再有2种语言,再加上词汇吗?还有一些北欧语言有15种语言。我很喜欢在.NET中看到该实现。
Stefan Steiger,2015年

22

我的Jesse版本的Stu版本和samjudson版本的:)

包含的单元测试表明,当数字<1时,可接受的答案不正确

    /// <summary>
    /// Get the ordinal value of positive integers.
    /// </summary>
    /// <remarks>
    /// Only works for english-based cultures.
    /// Code from: http://stackoverflow.com/questions/20156/is-there-a-quick-way-to-create-ordinals-in-c/31066#31066
    /// With help: http://www.wisegeek.com/what-is-an-ordinal-number.htm
    /// </remarks>
    /// <param name="number">The number.</param>
    /// <returns>Ordinal value of positive integers, or <see cref="int.ToString"/> if less than 1.</returns>
    public static string Ordinal(this int number)
    {
        const string TH = "th";
        string s = number.ToString();

        // Negative and zero have no ordinal representation
        if (number < 1)
        {
            return s;
        }

        number %= 100;
        if ((number >= 11) && (number <= 13))
        {
            return s + TH;
        }

        switch (number % 10)
        {
            case 1: return s + "st";
            case 2: return s + "nd";
            case 3: return s + "rd";
            default: return s + TH;
        }
    }

    [Test]
    public void Ordinal_ReturnsExpectedResults()
    {
        Assert.AreEqual("-1", (1-2).Ordinal());
        Assert.AreEqual("0", 0.Ordinal());
        Assert.AreEqual("1st", 1.Ordinal());
        Assert.AreEqual("2nd", 2.Ordinal());
        Assert.AreEqual("3rd", 3.Ordinal());
        Assert.AreEqual("4th", 4.Ordinal());
        Assert.AreEqual("5th", 5.Ordinal());
        Assert.AreEqual("6th", 6.Ordinal());
        Assert.AreEqual("7th", 7.Ordinal());
        Assert.AreEqual("8th", 8.Ordinal());
        Assert.AreEqual("9th", 9.Ordinal());
        Assert.AreEqual("10th", 10.Ordinal());
        Assert.AreEqual("11th", 11.Ordinal());
        Assert.AreEqual("12th", 12.Ordinal());
        Assert.AreEqual("13th", 13.Ordinal());
        Assert.AreEqual("14th", 14.Ordinal());
        Assert.AreEqual("20th", 20.Ordinal());
        Assert.AreEqual("21st", 21.Ordinal());
        Assert.AreEqual("22nd", 22.Ordinal());
        Assert.AreEqual("23rd", 23.Ordinal());
        Assert.AreEqual("24th", 24.Ordinal());
        Assert.AreEqual("100th", 100.Ordinal());
        Assert.AreEqual("101st", 101.Ordinal());
        Assert.AreEqual("102nd", 102.Ordinal());
        Assert.AreEqual("103rd", 103.Ordinal());
        Assert.AreEqual("104th", 104.Ordinal());
        Assert.AreEqual("110th", 110.Ordinal());
        Assert.AreEqual("111th", 111.Ordinal());
        Assert.AreEqual("112th", 112.Ordinal());
        Assert.AreEqual("113th", 113.Ordinal());
        Assert.AreEqual("114th", 114.Ordinal());
        Assert.AreEqual("120th", 120.Ordinal());
        Assert.AreEqual("121st", 121.Ordinal());
        Assert.AreEqual("122nd", 122.Ordinal());
        Assert.AreEqual("123rd", 123.Ordinal());
        Assert.AreEqual("124th", 124.Ordinal());
    }

15

简单,干净,快捷

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

或更好,作为一种扩展方法

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

现在你可以打电话

int a = 1;
a.DisplayWithSuffix(); 

甚至直接

1.DisplayWithSuffix();

14

您必须自己动手。从我的头顶:

public static string Ordinal(this int number)
{
  var work = number.ToString();
  if ((number % 100) == 11 || (number % 100) == 12 || (number % 100) == 13)
    return work + "th";
  switch (number % 10)
  {
    case 1: work += "st"; break;
    case 2: work += "nd"; break;
    case 3: work += "rd"; break;
    default: work += "th"; break;
  }
  return work;
}

然后你可以做

Console.WriteLine(432.Ordinal());

针对11/12/13例外进行了编辑。我想从头顶说:-)

针对1011版进行了编辑-其他人已经解决了此问题,只是想确保其他人不会抓住这个错误的版本。


12

我宁愿喜欢Stusamjudson的解决方案中的元素,也将它们组合成我认为是可用的组合:

    public static string Ordinal(this int number)
    {
        const string TH = "th";
        var s = number.ToString();

        number %= 100;

        if ((number >= 11) && (number <= 13))
        {
            return s + TH;
        }

        switch (number % 10)
        {
            case 1:
                return s + "st";
            case 2:
                return s + "nd";
            case 3:
                return s + "rd";
            default:
                return s + TH;
        }
    }

1
为“ th”使用常量的背后原理是什么?
尼克

因为它在代码中使用了两次。只是利用了您不应该重复自己的古老观点:)在这种情况下,.NET运行时仅应创建字符串的一个副本,而在代码中带有两个“ th”的情况下,将创建两个字符串并在内存中引用。
Jesse C. Slicer

25
而且,如果TH的值发生变化,将进行设置。

7
@Jesse-您得到+1,但我不相信.NET以这种方式处理字符串,请参见yoda.arachsys.com/csharp/strings.html#interning,我的读物是对第“ th”个字面量的引用将引用相同的内存位。但是我同意DRY :)
si618

4
我认为删除这样的重复只会阻碍可读性,因此造成了“为什么使用TH?”的困惑。我不认为DRY应该被解释为“不惜一切代价消除所有重复”。
SeeNoWeevil

8

尽管我还没有对此进行基准测试,但是应该避免所有条件案例语句,从而获得更好的性能。

这是java,但是C#的端口很简单:

public class NumberUtil {
  final static String[] ORDINAL_SUFFIXES = {
    "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
  };

  public static String ordinalSuffix(int value) {
    int n = Math.abs(value);
    int lastTwoDigits = n % 100;
    int lastDigit = n % 10;
    int index = (lastTwoDigits >= 11 && lastTwoDigits <= 13) ? 0 : lastDigit;
    return ORDINAL_SUFFIXES[index];
  }

  public static String toOrdinal(int n) {
    return new StringBuffer().append(n).append(ordinalSuffix(n)).toString();
  }
}

请注意,如果在紧密循环中生成大量的序数,则减少条件数和使用数组查找应可提高性能。但是,我也承认这不像case语句解决方案那样可读。


抱歉,我在C#中对此进行了基准测试,您的版本并不比si618的解决方案快。
GY_

检查此答案stackoverflow.com/a/58378465/2583579以获得某些基准测试
Dan Dohotaru

3

与Ryan的解决方案类似,但更基本,我只是使用一个简单的数组并使用一天来查找正确的序数:

private string[] ordinals = new 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" };
DateTime D = DateTime.Now;
String date = "Today's day is: "+ D.Day.ToString() + ordinals[D.Day];

我没有这个需要,但是如果您想获得多种语言支持,我想您可以使用多维数组。

从我上大学的时候就可以记住,此方法需要服务器的最少工作。


2

我使用这个扩展类:

public static class Int32Extensions
{
    public static string ToOrdinal(this int i)
    {
        return (i + "th")
            .Replace("1th", "1st")
            .Replace("2th", "2nd")
            .Replace("3th", "3rd");
    }
}

11st

2

要求samjudson答案的“较少冗余”版本...

public static string AddOrdinal(int number)
{
    if (number <= 0) return number.ToString();

    string GetIndicator(int num)
    {
        switch (num % 100)
        {
            case 11:
            case 12:
            case 13:
                return "th";
        }

        switch (num % 10)
        {
            case 1:
                return "st";
            case 2:
                return "nd";
            case 3:
                return "rd";
            default:
                return "th";
        }
    }

    return number + GetIndicator(number);
}

2
我将“ GetIndicator”公开为a public static,并将其重命名为一个更易记的名称(即“ OrdinalSuffix”)。呼叫者可能希望号码部分采用不同的格式(即逗号)。
汤姆(Tom),

2
        private static string GetOrd(int num) => $"{num}{(!(Range(11, 3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num % 10)) ? new[] { "ˢᵗ", "ⁿᵈ", "ʳᵈ" }[num % 10 - 1] : "ᵗʰ")}";

如果有人正在寻找一个班轮:p


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

1

编辑:正如YM_Industries在评论中指出的那样,samjudson的答案确实适用于超过1000的数字,尼克的评论似乎已经消失了,我不记得我看到的问题是什么。在这里将这个答案留作比较时间。

正如nickf在评论中指出的那样,其中很多都不适用于大于999的数字(编辑:现在丢失)。

这是基于关闭的修改版本的版本samjudson接受的答案是不。

public static String GetOrdinal(int i)
{
    String res = "";

    if (i > 0)
    {
        int j = (i - ((i / 100) * 100));

        if ((j == 11) || (j == 12) || (j == 13))
            res = "th";
        else
        {
            int k = i % 10;

            if (k == 1)
                res = "st";
            else if (k == 2)
                res = "nd";
            else if (k == 3)
                res = "rd";
            else
                res = "th";
        }
    }

    return i.ToString() + res;
}

此外沙赫扎德库雷希答案使用字符串操作能正常工作,但它确实有性能上的损失。为了生成大量这样的代码,LINQPad示例程序使字符串版本比此整数之一慢6到7倍(尽管您必须产生很多注意)。

LINQPad示例:

void Main()
{
    "Examples:".Dump();

    foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 10000013 })
        Stuff.GetOrdinal(i).Dump();

    String s;

    System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();

    for(int iter = 0; iter < 100000; iter++)
        foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 1000013 })
            s = Stuff.GetOrdinal(i);

    "Integer manipulation".Dump();
    sw.Elapsed.Dump();

    sw.Restart();

    for(int iter = 0; iter < 100000; iter++)
        foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 1000013 })
            s = (i.ToString() + Stuff.GetOrdinalSuffix(i));

    "String manipulation".Dump();
    sw.Elapsed.Dump();
}

public class Stuff
{
        // Use integer manipulation
        public static String GetOrdinal(int i)
        {
                String res = "";

                if (i > 0)
                {
                        int j = (i - ((i / 100) * 100));

                        if ((j == 11) || (j == 12) || (j == 13))
                                res = "th";
                        else
                        {
                                int k = i % 10;

                                if (k == 1)
                                        res = "st";
                                else if (k == 2)
                                        res = "nd";
                                else if (k == 3)
                                        res = "rd";
                                else
                                        res = "th";
                        }
                }

                return i.ToString() + res;
        }

        // Use string manipulation
        public static string GetOrdinalSuffix(int num)
        {
                if (num.ToString().EndsWith("11")) return "th";
                if (num.ToString().EndsWith("12")) return "th";
                if (num.ToString().EndsWith("13")) return "th";
                if (num.ToString().EndsWith("1")) return "st";
                if (num.ToString().EndsWith("2")) return "nd";
                if (num.ToString().EndsWith("3")) return "rd";
                return "th";
        }
}

我找不到@nickf的评论,samjudson的答案出了什么问题?在我看来,它可以处理1000以上的数字,并且比您的可读性更好。
约书亚·沃尔什

1
这是一个公平的评论,我只是运行了一个测试仪,却没有发现任何问题。似乎也没有对Sam的答案进行任何编辑,因此我只能想象自己会发疯。我已经修改了答案以反映这一点。
Whekaholism

1
哈哈,我们所有人都有这样的时刻,不是吗?我们回头看旧代码,然后转到“为什么我要写这个?”
约书亚·沃尔什

1

基于其他答案:

public static string Ordinal(int n)
{   
    int     r = n % 100,     m = n % 10;

    return (r<4 || r>20) && (m>0 && m<4) ? n+"  stndrd".Substring(m*2,2) : n+"th";                                              
}

3
第一名:最不必要的隐秘答案。“不必要”:代码大小/性能优势不值得阅读成本。“隐秘”:需要大量翻译才能映射到“ Layperson”要求。
汤姆(Tom),

0

FWIW,对于MS-SQL,此表达式可以完成工作。将第一个WHEN(WHEN num % 100 IN (11, 12, 13) THEN 'th')保留为列表中的第一个,因为这取决于在其他命令之前进行的尝试。

CASE
  WHEN num % 100 IN (11, 12, 13) THEN 'th' -- must be tried first
  WHEN num % 10 = 1 THEN 'st'
  WHEN num % 10 = 2 THEN 'nd'
  WHEN num % 10 = 3 THEN 'rd'
  ELSE 'th'
END AS Ordinal

对于Excel:

=MID("thstndrdth",MIN(9,2*RIGHT(A1)*(MOD(A1-11,100)>2)+1),2)

(MOD(A1-11,100)>2)对于所有以11,12,13(FALSE = 0)结尾的数字,表达式 均为TRUE(1 )。因此2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1),对于11/12/13最终为1,否则:
1 等于3
2到5、3
到7 等于3
:9-
"thstndrdth"从该位置开始选择所需的2个字符。

如果您真的想将其直接转换为SQL,这对我来说适用于少数测试值:

DECLARE @n as int
SET @n=13
SELECT SubString(  'thstndrdth'
                 , (SELECT MIN(value) FROM
                     (SELECT 9 as value UNION
                      SELECT 1+ (2* (ABS(@n) % 10)  *  CASE WHEN ((ABS(@n)+89) % 100)>2 THEN 1 ELSE 0 END)
                     ) AS Mins
                   )
                 , 2
                )

0

这是的实现dart,可以根据语言进行修改。

String getOrdinalSuffix(int num){
    if (num.toString().endsWith("11")) return "th";
    if (num.toString().endsWith("12")) return "th";
    if (num.toString().endsWith("13")) return "th";
    if (num.toString().endsWith("1")) return "st";
    if (num.toString().endsWith("2")) return "nd";
    if (num.toString().endsWith("3")) return "rd";
    return "th";
}

0

尽管这里有很多不错的答案,但我想这还有一个余地,这一次是基于模式匹配的,如果没有其他目的,那么至少是值得商bat的可读性

    public static string Ordinals1(this int number)
    {
        switch (number)
        {
            case int p when p % 100 == 11:
            case int q when q % 100 == 12:
            case int r when r % 100 == 13:
                return $"{number}th";
            case int p when p % 10 == 1:
                return $"{number}st";
            case int p when p % 10 == 2:
                return $"{number}nd";
            case int p when p % 10 == 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

是什么使该解决方案与众不同?我只不过是为其他各种解决方案添加了一些性能考虑因素而已

坦率地说,我怀疑性能对于这种特定情况(确实需要数以百万计的序数)是否真的很重要,但至少它会浮现出一些需要考虑的比较...

一百万个项目供您参考(您的研磨机可能会根据机器规格而有所不同)

具有模式匹配和除法(此答案)

〜622毫秒

与模式匹配和字符串(此答案)

〜1967毫秒

有两个开关和分区(可接受的答案)

〜637毫秒

一键切换和除法(另一种答案)

〜725毫秒

void Main()
{
    var timer = new Stopwatch();
    var numbers = Enumerable.Range(1, 1000000).ToList();

    // 1
    timer.Reset();
    timer.Start();
    var results1 = numbers.Select(p => p.Ordinals1()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and divisions");

    // 2
    timer.Reset();
    timer.Start();
    var results2 = numbers.Select(p => p.Ordinals2()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and strings");

    // 3
    timer.Reset();
    timer.Start();
    var results3 = numbers.Select(p => p.Ordinals3()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with two switches and divisons");

    // 4
    timer.Reset();
    timer.Start();
    var results4 = numbers.Select(p => p.Ordinals4()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with one switche and divisons");
}

public static class Extensions
{
    public static string Ordinals1(this int number)
    {
        switch (number)
        {
            case int p when p % 100 == 11:
            case int q when q % 100 == 12:
            case int r when r % 100 == 13:
                return $"{number}th";
            case int p when p % 10 == 1:
                return $"{number}st";
            case int p when p % 10 == 2:
                return $"{number}nd";
            case int p when p % 10 == 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

    public static string Ordinals2(this int number)
    {
        var text = number.ToString();
        switch (text)
        {
            case string p when p.EndsWith("11"):
                return $"{number}th";
            case string p when p.EndsWith("12"):
                return $"{number}th";
            case string p when p.EndsWith("13"):
                return $"{number}th";
            case string p when p.EndsWith("1"):
                return $"{number}st";
            case string p when p.EndsWith("2"):
                return $"{number}nd";
            case string p when p.EndsWith("3"):
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

    public static string Ordinals3(this int number)
    {
        switch (number % 100)
        {
            case 11:
            case 12:
            case 13:
                return $"{number}th";
        }

        switch (number % 10)
        {
            case 1:
                return $"{number}st";
            case 2:
                return $"{number}nd";
            case 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

    public static string Ordinals4(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}th";
            case 2:
                return $"{number}nd";
            case 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }
}

0

另一个单行代码,但不进行比较,只将正则表达式索引到数组中。

public static string GetOrdinalSuffix(int input)
{
    return new []{"th", "st", "nd", "rd"}[Convert.ToInt32("0" + Regex.Match(input.ToString(), "(?<!1)[1-3]$").Value)];
}

PowerShell版本可以进一步缩短:

function ord($num) { return ('th','st','nd','rd')[[int]($num -match '(?<!1)[1-3]$') * $matches[0]] }

0

另外1个班轮。

public static string Ordinal(this int n)
{    
 return n + (new [] {"st","nd","rd" }.ElementAtOrDefault((((n + 90) % 100 - 10) % 10 - 1)) ?? "th");
}

-2

这是DateTime扩展类。复制,粘贴和欣赏

公共静态类DateTimeExtensions {

    public static string ToStringWithOrdinal(this DateTime d)
    {
        var result = "";
        bool bReturn = false;            

        switch (d.Day % 100)
        {
            case 11:
            case 12:
            case 13:
                result = d.ToString("dd'th' MMMM yyyy");
                bReturn = true;
                break;
        }

        if (!bReturn)
        {
            switch (d.Day % 10)
            {
                case 1:
                    result = d.ToString("dd'st' MMMM yyyy");
                    break;
                case 2:
                    result = d.ToString("dd'nd' MMMM yyyy");
                    break;
                case 3:
                    result = d.ToString("dd'rd' MMMM yyyy");
                    break;
                default:
                    result = d.ToString("dd'th' MMMM yyyy");
                    break;
            }

        }

        if (result.StartsWith("0")) result = result.Substring(1);
        return result;
    }
}

结果:

2014年10月9日


您正在复制:a)日期格式字符串(X5),b)方法的其余部分(当可能的用例出现(如果尚未出现)时,非“月”需要一个序数后缀目的或什至是使用不同日期格式字符串的每月某天)。我建议使用“ OrdinalSuffix”方法从伊恩·沃伯顿(Ian Warburton)的17年4月6日下午16点32分公开(stackoverflow.com/questions/20156/…)。
汤姆,

-3

我根据所有其他建议使用的另一个替代方法,但不需要特殊的大小写:

    public static string DateSuffix(int day)
    {
        if (day == 11 | day == 12 | day == 13) return "th";
        Math.DivRem(day, 10, out day);
        switch (day)
        {
            case 1:
                return "st";
            case 2:
                return "nd";
            case 3:
                return "rd";
            default:
                return "th";
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.