Getting day suffix when using DateTime.ToString()
Asked Answered
L

21

103

Is it possible to include the day suffix when formatting a date using DateTime.ToString()?

For example I would like to print the date in the following format - Monday 27th July 2009. However the closest example I can find using DateTime.ToString() is Monday 27 July 2009.

Can I do this with DateTime.ToString() or am I going to have to fall back to my own code?

Lightfoot answered 12/1, 2010 at 17:10 Comment(4)
Did someone say NodaTime?Demerol
FYI, "[date] ordinal suffix" is what these are called. "Day" typically refers to Monday-SundayThapsus
@Demerol I want this to be the answer so bad. I've been searching for the better part of an hour to format NodaTime as mentioned in the question, but as far as I can tell it doesn't work: nodatime.org/2.3.x/userguide/localdate-patterns (even in 2020) It looks like momentjs has this because they built their own localization model: momentjs.com/docs/#/i18nApiece
nodatime.org/3.0.x/userguide/limitations Additionally, all our text localization resources (day and month names) come from the .NET framework itself. That has some significant limitations, and makes Noda Time more reliant on CultureInfo than is ideal. CLDR contains more information, which should allow for features such as ordinal day numbers ("1st", "2nd", "3rd") and a broader set of supported calendar/culture combinations (such as English names for the Hebrew calendar months).Apiece
C
71

As a reference I always use/refer to [SteveX String Formatting] 1 and there doesn't appear to be any "th" in any of the available variables but you could easily build a string with

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

You would then have to supply a "st" for 1, "nd" for 2, "rd" for 3, and "th" for all others and could be in-lined with a "? :" statement.

var now = DateTime.Now;
(now.Day % 10 == 1 && now.Day % 100 != 11) ? "st"
: (now.Day % 10 == 2 && now.Day % 100 != 12) ? "nd"
: (now.Day % 10 == 3 && now.Day % 100 != 13) ? "rd"
: "th"
Connecticut answered 12/1, 2010 at 17:17 Comment(6)
This would need to be further expanded to cover the other cases, otherwise you'll end up with "21th", for example.Acapulco
For what it's worth, Microsoft's official documentation of string formatting options can be found here.Fulmination
DateTime.Now is retrieved several times in the same expression, the values can be different if the code is executed around midnight.Heaume
I fixed the code to work with numbers over 100 so you will now get 112th instead of 112nd.Encroach
@Encroach I think there no Day of a Date above 100, check Microsoft Doc learn.microsoft.com/en-us/dotnet/api/system.datetime.day The Previous edit for answer must be the correct one: stackoverflow.com/revisions/2050854/4 and re-back your changesThrenody
@Fulmination That link is broken.Ridgley
S
278

Another option using switch:

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";
    }
}
Snooperscope answered 3/2, 2012 at 14:24 Comment(6)
+1 Simple, easy to read, and most importantly, works for all cases.Exclaim
@Snooperscope In case you are wondering about the sudden activity: your answer was linked as an "how to do it right" example by The Daily WTF.Transitory
@Transitory thanks - I wondered how my minuscule reputation had doubled so quickly!Snooperscope
For those who want the full date formatting: return date.ToString("dd MMMM yyyy").Insert(2, GetDaySuffix(date.Day)); //e.g 12th January 2020Handbook
Needed this and am I am glad I found it but just sad that this formatting hasn't been updated in .NET6 still. particularly because I need this with localization.Retractile
@Retractile What solution did you finally found?Christophany
C
71

As a reference I always use/refer to [SteveX String Formatting] 1 and there doesn't appear to be any "th" in any of the available variables but you could easily build a string with

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

You would then have to supply a "st" for 1, "nd" for 2, "rd" for 3, and "th" for all others and could be in-lined with a "? :" statement.

var now = DateTime.Now;
(now.Day % 10 == 1 && now.Day % 100 != 11) ? "st"
: (now.Day % 10 == 2 && now.Day % 100 != 12) ? "nd"
: (now.Day % 10 == 3 && now.Day % 100 != 13) ? "rd"
: "th"
Connecticut answered 12/1, 2010 at 17:17 Comment(6)
This would need to be further expanded to cover the other cases, otherwise you'll end up with "21th", for example.Acapulco
For what it's worth, Microsoft's official documentation of string formatting options can be found here.Fulmination
DateTime.Now is retrieved several times in the same expression, the values can be different if the code is executed around midnight.Heaume
I fixed the code to work with numbers over 100 so you will now get 112th instead of 112nd.Encroach
@Encroach I think there no Day of a Date above 100, check Microsoft Doc learn.microsoft.com/en-us/dotnet/api/system.datetime.day The Previous edit for answer must be the correct one: stackoverflow.com/revisions/2050854/4 and re-back your changesThrenody
@Fulmination That link is broken.Ridgley
J
47

Using a couple of extension methods:

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

Usage:

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

Note: The integer extension method can be used for any number, not just 1 to 31. e.g.

return 332211.ToOccurrenceSuffix();
// th
Jany answered 7/3, 2014 at 9:10 Comment(4)
Thanks Buddy. Much Helpful. I have implemented in my project. :)Twotime
Your code kind of... forgets to check the useExtendedSpecifiers boolean :pNecrology
The most elegant solution. This is exactly what extension methods are designed for. Have added to my ever growing extension method library, thanks!Thermaesthesia
ToOrdinal(), maybe? :)Coinsure
C
14

Another option is using the 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;
}

You would then call the above method by passing-in a DateTime object as a parameter, for example:

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

For more info about the DateTime constructor, please see Microsoft Docs Page.

Canoodle answered 28/1, 2012 at 15:21 Comment(4)
@Greg That's strange as var suffix = CreateDateSuffix(new DateTime(2013, 10, 8)); returns '8th' in my case?Canoodle
If it were appending 'th' to the string 'eight' it would be wrong, but in this case since you used the digit 8 it is correct.York
The above method as it stands takes a DateTime object and I cannot see how it could be instantiated with anything other than numeric values - in this case '8' representing the day of the month.Canoodle
In that case, it's correct. If you were to, I don't know, replace the numeric value with the textual representation of the number, it would be wrong. I suppose that's up to whoever is doing the replacing though, to know this and replace '8t' with 'eight', or more correctly, replace '8' with 'eigh'.York
T
8

Here is extended version including 11th, 12th and 13th:

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";
Taurus answered 11/10, 2011 at 16:0 Comment(4)
and what about "11th", "12th" and "13th"?Oxbow
I must have missed this. I fixed that above.Taurus
FYI if this was needed for numbers greater than ("dd") would produce, use string.PadLeft()Esra
@PiotrLewandowski - You not from Manchester by any chance? Cause I know one from there. Too freaky +1 btwWondering
R
8

Taking @Lazlow's answer to a complete solution, the following is a fully reusable extension method, with example usage;

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

To use this you would simply call it on a DateTime object;

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

Which will give you:

Friday 17th June 2016

Ron answered 17/6, 2016 at 12:19 Comment(0)
F
6

UPDATE

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

Example:
https://dotnetfiddle.net/zXQX7y

Supports:
.NET Core 1.0 and higher
.NET Framework 4.5 and high


Here's an extension method (because everyone loves extension methods), with Lazlow's answer as the basis (picked Lazlow's as it's easy to read).

Works just like the regular ToString() method on DateTime with the exception that if the format contains a d or dd, then the suffix will be added automatically.

/// <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);
}
Freer answered 21/2, 2014 at 6:12 Comment(2)
Surprised that this hasn't got more up votes, I prefer the fact that it's an extension. Makes it much easier to use and arguably more readable.Stannfield
That NuGet Package doesn't like formats which include ddd or dddd - ie the name of the weekday. If you want to display a date as 'Thursday 4th November 2021' you need to work around that limitation - eg Console.WriteLine(DateTime.UtcNow.ToString("dddd")+" "+DateTime.UtcNow.ToStringWithSuffix("d MMMM yyyy")); Embrocation
L
4

Simpler answer using a switch expression (since C# 8):

var daySuffix = dateTime.Day switch {
                    1 or 21 or 31 => "st",
                    2 or 22 => "nd",
                    3 or 23 => "rd",
                    _ => "th",
                };
Legate answered 18/2, 2022 at 14:41 Comment(1)
what if i want to use a number ending in 1 that is larger than 31... 41 for example ;)Book
P
2

I believe this to be a good solution, covering numbers such as 111th etc:

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;
}
Preindicate answered 11/1, 2013 at 11:44 Comment(1)
Although this is a more general purpose method, for any number, not just month days (I think).Preindicate
S
2

For those who are happy to use external dependencies (in this case the fantastic Humanizr .net), it's as simple as

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

Sanguine answered 14/11, 2019 at 13:37 Comment(1)
Wonderful suggestion. I wish this was built in to .NET.Ridgley
O
1

public static String SuffixDate(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;
     }
     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);
  }
Ofilia answered 21/3, 2017 at 0:34 Comment(1)
This version shows only the first digit of a day ie 1st March 2017 where I didn't want the day name first as in a long date and didn't want the 01st instead of 1stOfilia
I
0

For what its worth here is my final solution using the below answers

     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"); 
Informer answered 11/11, 2013 at 10:59 Comment(0)
E
0

Get Date Suffix. (Static Function)

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

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

Enthronement answered 13/2, 2018 at 19:43 Comment(0)
A
0

Check out 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"

I realized right after posting this that @Gumzle suggested the same thing, but I missed his post because it was buried in code snippets. So this is his answer with enough code that someone (like me) quickly scrolling through might see it.

Apiece answered 19/8, 2020 at 16:39 Comment(0)
E
0

A solution you can use in a razor template. It's probably not the most elegant way but it's quick and it works

@Model.Pubdate.ToString("dddd, d'th' MMMM yyyy").Replace("1th","1st").Replace("2th", "2nd").Replace("3th", "3rd").Replace("11st", "11th").Replace("12nd", "12th").Replace("13rd", "13th")

ToString("dddd, d'th' MMMM yyyy") adds "th" after the day number, eg "Tuesday, 31th May 2022". Then use a set of string replacements to change 1th, 2th and 3th to 1st, 2nd and 3rd, and another set to change 11st, 12nd and 13rd back to 11th, 12th and 13th.

Embrocation answered 27/5, 2022 at 11:19 Comment(0)
F
0

A nice solution if you want a date in the format "28th September 2023":

public static string FormatDateWithSuffix(DateTime? date)
{
if (!date.HasValue)
    return "";

int day = date.Value.Day;
string suffix = day switch
{
    1 or 21 or 31 => "st",
    2 or 22 => "nd",
    3 or 23 => "rd",
    _ => "th",
};
return date.Value.ToString($"d{suffix} MMMM yyyy");
}
Far answered 19/12, 2023 at 10:14 Comment(0)
T
-1

A cheap and cheerful VB solution:

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
Torosian answered 14/3, 2013 at 13:59 Comment(0)
I
-1

I did it like this, it gets around some of the problems given in the other examples.

    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";
        }
    }
Ingressive answered 22/3, 2013 at 11:13 Comment(0)
S
-1
string datestring;    
// datestring = DateTime.Now.ToString("dd MMMM yyyy"); // 16 January 2021

    // code to add 'st' ,'nd', 'rd' and 'th' with day of month 
    // DateTime todaysDate = DateTime.Now.Date; // enable this line for current date 
    DateTime todaysDate = DateTime.Parse("01-13-2021"); // custom date to verify code // 13th January 2021
    int day = todaysDate.Day;
    string dateSuffix;

    if(day==1 || day==21 || day==31){
        dateSuffix= "st";
    }else if(day==2 || day==22 ){
        dateSuffix= "nd";
    }else if(day==3 || day==23 ){
        dateSuffix= "rd";
    }else{
        dateSuffix= "th";
    }
    datestring= day+dateSuffix+" "+todaysDate.ToString("MMMM")+" "+todaysDate.ToString("yyyy");
    Console.WriteLine(datestring);
Stonebroke answered 16/1, 2021 at 13:13 Comment(0)
I
-4

Another option using the last string character:

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;
}
Irremeable answered 11/10, 2012 at 13:19 Comment(2)
Thanks AakashM your right, I've editted to correct the mistake.Irremeable
Now it gives 1th, 2th, and 3th.Ume
D
-5

in the MSDN documentation there is no reference to a culture that could convert that 17 into 17th. so You should do it manually via code-behind.Or build one...you could build a function that does that.

public string CustomToString(this DateTime date)
    {
        string dateAsString = string.empty;
        <here wright your code to convert 17 to 17th>
        return dateAsString;
    }
Dibucaine answered 12/1, 2010 at 17:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.