使用DateTime.ToString()时获取日后缀


78

使用DateTime.ToString()格式化日期时,是否可以包含日期后缀?

例如,我想以以下格式打印日期-2009年7月27日星期一。但是,使用DateTime.ToString()找到的最接近的示例是2009年7月27日星期一。

我可以使用DateTime.ToString()进行此操作,还是必须退回到我自己的代码?


7
有人说过NodaTime吗?
手榴弹

2
仅供参考,这些称为“ [日期]序号后缀”。“白天”通常是指周一至周日
理查德·萨雷

@grenade我希望这可以成为答案。我一直在寻找一个小时的大部分时间来格式化问题中提到的NodaTime,但据我所知它不起作用:nodatime.org/2.3.x/userguide/localdate-patterns(即使在2020年),momentjs似乎拥有这个,因为他们建立了自己的本地化模型:momentjs.com/docs
德鲁·德拉诺

nodatime.org/3.0.x/userguide/limitations 此外,我们所有的文本本地化资源(日期和月份名称)都来自.NET框架本身。这有一些明显的局限性,并使Noda Time更加依赖CultureInfo而不是理想的解决方案。CLDR包含更多信息,这些信息应具有序数天数(“ 1st”,“ 2nd”,“ 3rd”)和更广泛的受支持的日历/文化组合(例如希伯来历月的英文名称)等功能。
德鲁·德拉诺

Answers:


64

作为参考,我始终使用/参考SteveX字符串格式, 并且在任何可用变量中似乎都没有“ th”,但是您可以轻松地使用

string.Format("{0:dddd dd}{1} {0:MMMM yyyy}", DateTime.Now, (?));

然后,您必须为1提供一个“ st”,为2提供一个“ nd”,为所有其他提供一个“ rd”,并为所有其他提供“ th”,并且可以用“?:”语句内联。

var now = DateTime.Now;
(now.Day % 10 == 1 && now.Day != 11) ? "st"
: (now.Day % 10 == 2 && now.Day != 12) ? "nd"
: (now.Day % 10 == 3 && now.Day != 13) ? "rd"
: "th"

22
这将需要进一步扩展以涵盖其他情况,否则,例如,您最终将获得“ 21th”。
Kasaku

1
值得一提的是,可以在此处找到Microsoft的字符串格式选项官方文档。
Bobson,2012年

9
DateTime.Now在同一个表达式中被多次检索,如果代码在午夜左右执行,则值可以不同。
AlexD

244

使用开关的另一种选择:

string GetDaySuffix(int day)
{
    switch (day)
    {
        case 1:
        case 21:
        case 31:
            return "st";
        case 2:
        case 22:
            return "nd";
        case 3:
        case 23:
            return "rd";
        default:
            return "th";
    }
}

10
+1简单,易于阅读,最重要的是,它适用于所有情况。
Lynn在2013年

24
@Lazlow如果您想知道突然的活动:The Daily WTF将您的答案链接为“正确做事”的示例。
tobias_k 2013年

@tobias_k谢谢-我想知道我微不足道的声誉如何如此快地翻了一倍!
Lazlow

1
对于需要完整日期格式的用户:返回date.ToString(“ dd MMMM yyyy”)。Insert(2,GetDaySuffix(date.Day)); //例如2020
user3162879

39

使用几种扩展方法:

namespace System
{
    public static class IntegerExtensions
    {
        public static string ToOccurrenceSuffix(this int integer)
        {
            switch (integer % 100)
            {
                case 11:
                case 12:
                case 13:
                    return "th";
            }
            switch (integer % 10)
            {
                case 1:
                    return "st";
                case 2:
                    return "nd";
                case 3:
                    return "rd";
                default:
                    return "th";
            }
        }
    }   

    public static class DateTimeExtensions
    {
        public static string ToString(this DateTime dateTime, string format, bool useExtendedSpecifiers)
        {
            return useExtendedSpecifiers 
                ? dateTime.ToString(format)
                    .Replace("nn", dateTime.Day.ToOccurrenceSuffix().ToLower())
                    .Replace("NN", dateTime.Day.ToOccurrenceSuffix().ToUpper())
                : dateTime.ToString(format);
        } 
    }
}

用法:

return DateTime.Now.ToString("dddd, dnn MMMM yyyy", useExtendedSpecifiers: true);
// Friday, 7th March 2014

注意:整数扩展方法可以用于任何数字,而不仅仅是1到31。例如

return 332211.ToOccurrenceSuffix();
// th

1
谢谢,兄弟。很有帮助。我已经在我的项目中实现了。:)
Chandan Kumar 2014年

6
您的代码类型...忘记检查useExtendedSpecifiers布尔值:p
Nyerguds

2
最优雅的解决方案。这正是扩展方法设计的目的。已添加到我不断增长的扩展方法库中,谢谢!
Radderz

1
ToOrdinal(),也许吗?:)
Mladen B.

13

另一种选择是使用Modulo Operator

public string CreateDateSuffix(DateTime date)
{
    // Get day...
    var day = date.Day;

    // Get day modulo...
    var dayModulo = day%10;

    // Convert day to string...
    var suffix = day.ToString(CultureInfo.InvariantCulture);

    // Combine day with correct suffix...
    suffix += (day == 11 || day == 12 || day == 13) ? "th" :
        (dayModulo == 1) ? "st" :
        (dayModulo == 2) ? "nd" :
        (dayModulo == 3) ? "rd" :
        "th";

    // Return result...
    return suffix;
}

然后,您可以通过传入DateTime对象作为参数来调用上述方法,例如:

// Get date suffix for 'October 8th, 2019':
var suffix = CreateDateSuffix(new DateTime(2019, 10, 8));

有关DateTime构造函数的更多信息,请参见Microsoft Docs页面


2
@Gregvar suffix = CreateDateSuffix(new DateTime(2013, 10, 8));在我的情况下返回'8th'很奇怪吗?
安东尼·沃尔什

1
如果将'th'附加到字符串'eight'上,那将是错误的,但是在这种情况下,由于您使用了数字8,因此是正确的。
gcochard

上面的方法实际上需要一个DateTime对象,我看不到如何用数值以外的任何其他实例化它-在这种情况下,“ 8 ”表示月份中的某天。
安东尼·沃尔什

在这种情况下,这是正确的。我不知道,如果要用数字的文本表示形式替换数字值,那将是错误的。我想这取决于执行替换的人,要知道这一点并将“ 8t”替换为“八”,或更正确的是,将“ 8”替换为“ eigh”。
gcochard

7

这是扩展版本,包括11、12和13:

DateTime dt = DateTime.Now;
string d2d = dt.ToString("dd").Substring(1);
string daySuffix =
    (dt.Day == 11 || dt.Day == 12 || dt.Day == 13) ? "th"
    : (d2d == "1") ? "st"
    : (d2d == "2") ? "nd"
    : (d2d == "3") ? "rd"
    : "th";

那“ 11th”,“ 12th”和“ 13th”呢?
sjngm 2011年

我一定错过了。我在上面固定了。
Piotr Lewandowski

仅供参考,如果需要的数量大于("dd")产生的数量,请使用string.PadLeft()
maxp

@PiotrLewandowski-您不是来自曼彻斯特吗?因为我从那里认识一个。怪胎+1 btw
Piotr Kula

7

以@Lazlow的答案为一个完整的解决方案,以下是一个完全可重用的扩展方法,并带有示例用法;

internal static string HumanisedDate(this DateTime date)
{
    string ordinal;

    switch (date.Day)
    {
        case 1:
        case 21:
        case 31:
            ordinal = "st";
            break;
        case 2:
        case 22:
            ordinal = "nd";
            break;
        case 3:
        case 23:
            ordinal = "rd";
            break;
        default:
            ordinal = "th";
            break;
    }

    return string.Format("{0:dddd dd}{1} {0:MMMM yyyy}", date, ordinal);
} 

要使用它,您只需在一个DateTime对象上调用它即可;

var myDate = DateTime.Now();
var myDateString = myDate.HumanisedFormat()

这会给你:

2016年6月17日星期五


5

更新

NuGet包:https :
//www.nuget.org/packages/DateTimeToStringWithSuffix

示例:https
//dotnetfiddle.net/zXQX7y

支持:
.NET Core 1.0和更高版本
.NET Framework 4.5和更高版本


这是一种扩展方法(因为每个人都喜欢扩展方法),以Lazlow的答案为基础(因为易于阅读,所以选择了Lazlow的答案)。

与常规ToString()方法的工作原理相同DateTime,不同之处在于,如果格式包含ddd,则后缀将自动添加。

/// <summary>
/// Return a DateTime string with suffix e.g. "st", "nd", "rd", "th"
/// So a format "dd-MMM-yyyy" could return "16th-Jan-2014"
/// </summary>
public static string ToStringWithSuffix(this DateTime dateTime, string format, string suffixPlaceHolder = "$") {
    if(format.LastIndexOf("d", StringComparison.Ordinal) == -1 || format.Count(x => x == 'd') > 2) {
        return dateTime.ToString(format);
    }

    string suffix;
    switch(dateTime.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;
    }

    var formatWithSuffix = format.Insert(format.LastIndexOf("d", StringComparison.InvariantCultureIgnoreCase) + 1, suffixPlaceHolder);
    var date = dateTime.ToString(formatWithSuffix);

    return date.Replace(suffixPlaceHolder, suffix);
}

1
感到惊讶的是,这还没有得到更多的赞成票,我更喜欢它是一个扩展。使它更易于使用并且可以说更具可读性。
0Neji '16

2

我认为这是一个很好的解决方案,可以涵盖第111等数字:

private string daySuffix(int day)
{
    if (day > 0)
    {
        if (day % 10 == 1 && day % 100 != 11)
            return "st";
        else if (day % 10 == 2 && day % 100 != 12)
            return "nd";
        else if (day % 10 == 3 && day % 100 != 13)
            return "rd";
        else
            return "th";
    }
    else
        return string.Empty;
}

尽管这是一种更通用的方法,但对于任何数量,不仅是一个月的天(我认为)。
邓肯

1

对于那些乐于使用外部依赖关系的人(在这种情况下,使用出色的Humanizr .net),它就像

dateVar.Day.Ordinalize(); \\ 1st, 4th etc depending on the value of dateVar


0

我是这样做的,它解决了其他示例中给出的一些问题。

    public static string TwoLetterSuffix(this DateTime @this)
    {
        var dayMod10 = @this.Day % 10;

        if (dayMod10 > 3 || dayMod10 == 0 || (@this.Day >= 10 && @this.Day <= 19))
        {
            return "th";
        }
        else if(dayMod10 == 1)
        {
            return "st";
        }
        else if (dayMod10 == 2)
        {
            return "nd";
        }
        else
        {
            return "rd";
        }
    }

0

一种便宜而开朗的VB解决方案:

litDate.Text = DatePart("dd", Now) & GetDateSuffix(DatePart("dd", Now))

Function GetDateSuffix(ByVal dateIn As Integer) As String

    '// returns formatted date suffix

    Dim dateSuffix As String = ""
    Select Case dateIn
        Case 1, 21, 31
            dateSuffix = "st"
        Case 2, 22
            dateSuffix = "nd"
        Case 3, 23
            dateSuffix = "rd"
        Case Else
            dateSuffix = "th"
    End Select

    Return dateSuffix

End Function

0

对于它的价值,这是我使用以下答案的最终解决方案

     DateTime dt = DateTime.Now;
        string d2d = dt.ToString("dd").Substring(1); 

        string suffix =
       (dt.Day == 11 || dt.Day == 12 || dt.Day == 13) ? "th"
       : (d2d == "1") ? "st"
       : (d2d == "2") ? "nd"
       : (d2d == "3") ? "rd"
       : "th";


        Date.Text = DateTime.Today.ToString("dddd d") + suffix + " " + DateTime.Today.ToString("MMMM") + DateTime.Today.ToString(" yyyy"); 

0

公共静态字符串SuffixDate(DateTime date){字符串序号;

     switch (date.Day)
     {
        case 1:
        case 21:
        case 31:
           ordinal = "st";
           break;
        case 2:
        case 22:
           ordinal = "nd";
           break;
        case 3:
        case 23:
           ordinal = "rd";
           break;
        default:
           ordinal = "th";
           break;
     }
     if (date.Day < 10)
        return string.Format("{0:d}{2} {1:MMMM yyyy}", date.Day, date, ordinal);
     else
        return string.Format("{0:dd}{1} {0:MMMM yyyy}", date, ordinal);
  }

1
该版本仅显示一天的第一位数字,即2017年3月1日,在那我不想像长日期那样优先使用日名,也不想用01st代替1st
Robert Peter Bronstein

0

获取日期后缀。(静态功能)

public static string GetSuffix(this string day)
{
    string suffix = "th";

    if (int.Parse(day) < 11 || int.Parse(day) > 20)
    {
        day = day.ToCharArray()[day.ToCharArray().Length - 1].ToString();
        switch (day)
        {
            case "1":
                suffix = "st";
                break;
            case "2":
                suffix = "nd";
                break;
            case "3":
                suffix = "rd";
                break;
        }
    }

    return suffix;
}

参考:https : //www.aspsnippets.com/Articles/Display-st-nd-rd-and-th-suffix-after-day-numbers-in-Formatted-Dates-using-C-and-VBNet.aspx


0

看看humanizr:https : //github.com/Humanizr/Humanizer#date-time-to-ordinal-words

new DateTime(2015, 1, 1).ToOrdinalWords() => "1st January 2015"
new DateTime(2015, 2, 12).ToOrdinalWords() => "12th February 2015"
new DateTime(2015, 3, 22).ToOrdinalWords() => "22nd March 2015"
// for English US locale
new DateTime(2015, 1, 1).ToOrdinalWords() => "January 1st, 2015"
new DateTime(2015, 2, 12).ToOrdinalWords() => "February 12th, 2015"
new DateTime(2015, 3, 22).ToOrdinalWords() => "March 22nd, 2015"

在发布此内容后,我立即意识到@Gumzle提出了相同的建议,但我错过了他的帖子,因为它被埋在了代码片段中。因此,这是他的答案,其中包含足够的代码,使得像我这样的人可以快速滚动浏览该代码。


-2

使用最后一个字符串字符的另一个选项:

public static string getDayWithSuffix(int day) {
 string d = day.ToString();
 if (day < 11 || day > 13) {
  if (d.EndsWith("1")) {
   d += "st";
  } else if (d.EndsWith("2")) {
   d += "nd";
  } else if (d.EndsWith("3")) {
   d += "rd";
  } else {
   d += "th";
 } else {
  d += "th";
 }
 return d;
}

感谢AakashM您的权利,我已进行了更正,以更正此错误。
乔达,2012年

现在,它给人1th2th3th
AakashM

-4

在MSDN文档中,没有提到将17转换为17的文化。所以您应该通过代码隐藏手动进行操作,或者构建一个...可以构建一个执行此操作的函数。

public string CustomToString(this DateTime date)
    {
        string dateAsString = string.empty;
        <here wright your code to convert 17 to 17th>
        return dateAsString;
    }
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.