Отримання суфікса дня при використанні DateTime.ToString ()


80

Чи можна включити суфікс дня при форматуванні дати за допомогою DateTime.ToString ()?

Наприклад, я хотів би надрукувати дату у такому форматі - понеділок, 27 липня 2009 р. Однак найближчим прикладом, який я можу знайти за допомогою DateTime.ToString (), є понеділок, 27 липня 2009 р.

Чи можу я це зробити за допомогою DateTime.ToString (), або мені доведеться повернутися до власного коду?


7
Хтось сказав NodaTime?
граната

2
FYI, "так званий порядковий суфікс [дата]". "День" зазвичай відноситься до понеділка-неділі
Річарда Салая,

@grenade Я хочу, щоб це була така погана відповідь. Я шукав більшу частину години для форматування NodaTime, як згадувалось у питанні, але, наскільки я можу сказати, це не працює: nodatime.org/2.3.x/userguide/localdate-patterns (навіть у 2020) Схоже, у momentjs є це, бо вони створили власну модель локалізації: momentjs.com/docs/#/i18n
Дрю Делано,

nodatime.org/3.0.x/userguide/limitations Крім того, усі наші ресурси для локалізації тексту (імена днів та місяців) походять із самої платформи .NET. Це має деякі суттєві обмеження і робить Noda Time більш залежним від CultureInfo, ніж ідеально. CLDR містить більше інформації, яка повинна передбачати такі функції, як порядкові номери днів ("1-й", "2-й", "3-й"), а також ширший набір підтримуваних поєднань календаря / культури (наприклад, англійські назви для єврейських календарних місяців).
Дрю Делано,

Відповіді:


64

Як посилання я завжди використовую / посилаюся на Форматування рядків SteveX, і, здається, в жодній із доступних змінних немає жодного "-го", але ви можете легко побудувати рядок за допомогою

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

Тоді вам довелося б вказати "st" для 1, "nd" для 2, "rd" для 3, і "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
Це потрібно було б додатково розширити, щоб охопити інші випадки, інакше, наприклад, ви отримаєте "21-й".
Касаку,

1
Для того, що це варто, офіційну документацію Microsoft щодо варіантів форматування рядків можна знайти тут .
Бобсон

9
DateTime.Nowотримується кілька разів в одному і тому ж виразі, значення можуть бути різними, якщо код виконується близько опівночі.
AlexD

245

Інший варіант використання перемикача:

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 Простий, легкий для читання, а головне, працює для всіх випадків.
Лінн Крумблінг,

24
@Lazlow На випадок, якщо вам цікаво про раптову активність: вашу відповідь The Daily WTF посилає на приклад "як це зробити правильно" .
tobias_k

@tobias_k дякую - я дивувався, як моя мізерна репутація так швидко подвоїлася!
Лазлов

1
Для тих, хто бажає повного форматування дати: return date.ToString ("dd MMMM yyyy"). Insert (2, GetDaySuffix (date.Day)); // наприклад, 12 січня 2020 р
користувач3162879,

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
Дякую друже. Дуже корисно. Я реалізував у своєму проекті. :)
Чандан Кумар,

6
Ваш код ... забуває перевірити useExtendedSpecifiers
логічну формулу

2
Найелегантніше рішення. Саме для цього розроблені методи розширення. Додав до моєї постійно зростаючої бібліотеки методів розширення, дякую!
Раддерц

1
ToOrdinal (), може? :)
Младен Б.

13

Інший варіант - використання оператора Modulo :

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

Потім ви зателефонуєте вищезгаданому методу, передавши a DateTime як параметр, наприклад:

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

Для отримання додаткової інформації про конструктор DateTime , будь ласка, див. Сторінку Документи Microsoft .


2
@Greg Це дивно, оскільки var suffix = CreateDateSuffix(new DateTime(2013, 10, 8));у моєму випадку повертається "8-е"?
Ентоні Уолш,

1
Якби до рядка "вісім" було додано "й", це було б неправильно, але в цьому випадку, оскільки ви використовували цифру 8, це правильно.
gcochard

Вищевказаний метод, як він виглядає, приймає об'єкт DateTime, і я не бачу, як його можна створити з іншим, крім числових значень - у цьому випадку ' 8 ', що представляє день місяця.
Ентоні Уолш,

У такому випадку це правильно. Якби ви, не знаю, замінили числове значення текстовим поданням числа, це було б неправильно. Я припускаю, що це залежить від того, хто робить заміну, хоча це знатиме і замінить '8t' на 'вісім', або, вірніше, замінить '8' на 'вісім'.
gcochard

8

Ось розширена версія, що включає 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";

а як щодо "11-го", "12-го" та "13-го"?
sjngm

Напевно, я це пропустив. Я виправив це вище.
Piotr Lewandowski

FYI, якщо це було потрібно для чисел, більших, ніж це ("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()

Що дасть вам:

П’ятниця, 17 червня 2016 р


5

ОНОВЛЕННЯ

Пакет NuGet:
https://www.nuget.org/packages/DateTimeToStringWithSuffix

Приклад:
https://dotnetfiddle.net/zXQX7y

Підтримує:
.NET Core 1.0 і вище
.NET Framework 4.5 і вище


Ось метод розширення (оскільки всі люблять методи розширення), в основі якого - відповідь Лазлова (вибраний Лазлов, оскільки його легко читати).

Працює так само, як звичайний ToString()метод, за DateTimeвинятком того, що якщо формат містить dабо dd, то суфікс буде додано автоматично.

/// <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
Здивований, що це не набрало більше голосів, я віддаю перевагу тому факту, що це продовження. Це робить його набагато простішим у використанні та, можливо, більш читабельним.
0Неджі

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

public static String 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
Ця версія показує лише першу цифру дня, тобто 1 березня 2017 р., Де я не хотів, щоб назва дня була першою, як у довгій даті, і не хотіла 01-го замість 1-го
Роберт Пітер Бронштейн

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

Отримати суфікс дати. (Статична функція)

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 за ваше право, я відредагував виправлення помилки.
Джодда,

Тепер вона дає 1th, 2thі 3th.
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;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.