Obtener el sufijo de día al usar DateTime.ToString ()

80

¿Es posible incluir el sufijo de día al formatear una fecha usando DateTime.ToString ()?

Por ejemplo, me gustaría imprimir la fecha en el siguiente formato: lunes 27 de julio de 2009. Sin embargo, el ejemplo más cercano que puedo encontrar usando DateTime.ToString () es el lunes 27 de julio de 2009.

¿Puedo hacer esto con DateTime.ToString () o tendré que recurrir a mi propio código?

Craig Bovis
fuente
7
¿Alguien dijo NodaTime?
Granada
2
FYI, "sufijo ordinal de [fecha]" es como se llaman. "Día" normalmente se refiere a de lunes a domingo
Richard Szalay,
@grenade Quiero que esta sea la respuesta. He estado buscando la mayor parte de una hora para formatear NodaTime como se menciona en la pregunta, pero por lo que puedo decir, no funciona: nodatime.org/2.3.x/userguide/localdate-patterns (incluso en 2020) Parece que momentjs tiene esto porque construyeron su propio modelo de localización: momentjs.com/docs/#/i18n
Drew Delano
nodatime.org/3.0.x/userguide/limitations Además, todos nuestros recursos de localización de texto (nombres de días y meses) provienen del marco .NET. Eso tiene algunas limitaciones importantes y hace que Noda Time dependa más de CultureInfo de lo que es ideal. CLDR contiene más información, que debería permitir características tales como números de días ordinales ("1 °", "2 °", "3 °") y un conjunto más amplio de combinaciones de calendario / cultura admitidas (como nombres en inglés para los meses del calendario hebreo).
Drew Delano

Respuestas:

64

Como referencia, siempre uso / me refiero a SteveX String Formatting y no parece haber ninguna "th" en ninguna de las variables disponibles, pero podría construir fácilmente una cadena con

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

Entonces tendría que proporcionar una "st" para 1, "nd" para 2, "rd" para 3 y "th" para todos los demás y podría estar alineada con una declaración "?:".

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"
Bryan Bailliache
fuente
22
Esto debería ampliarse aún más para cubrir los otros casos; de lo contrario, terminará con "21", por ejemplo.
Kasaku
1
Por lo que vale, la documentación oficial de Microsoft sobre las opciones de formato de cadenas se puede encontrar aquí .
Bobson
9
DateTime.Nowse recupera varias veces en la misma expresión, los valores pueden ser diferentes si el código se ejecuta alrededor de la medianoche.
AlexD
245

Otra opción que usa el interruptor:

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";
    }
}
Lazlow
fuente
10
+1 Simple, fácil de leer y, lo más importante, funciona para todos los casos.
Lynn Crumbling
24
@Lazlow En caso de que se esté preguntando acerca de la actividad repentina: su respuesta fue vinculada como un ejemplo de "cómo hacerlo bien" por The Daily WTF .
tobias_k
@tobias_k gracias - ¡Me preguntaba cómo mi minúscula reputación se había duplicado tan rápido!
Lazlow
1
Para aquellos que deseen el formato de fecha completo: fecha de retorno.ToString ("dd MMMM aaaa"). Insert (2, GetDaySuffix (date.Day)); // por ejemplo, 12 de enero de 2020
user3162879
39

Usando un par de métodos de extensión:

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

Uso:

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

Nota: El método de extensión de enteros se puede utilizar para cualquier número, no solo del 1 al 31. p. Ej.

return 332211.ToOccurrenceSuffix();
// th
Oundless
fuente
1
Gracias amigo. Muy útil. Lo he implementado en mi proyecto. :)
Chandan Kumar
6
Su código es como ... se olvida de comprobar el useExtendedSpecifiersbooleano: p
Nyerguds
2
La solución más elegante. Esto es exactamente para lo que están diseñados los métodos de extensión. Lo he agregado a mi biblioteca de métodos de extensión en constante crecimiento, ¡gracias!
Radderz
1
ToOrdinal (), tal vez? :)
Mladen B.
13

Otra opción es usar el operador de módulo :

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

Luego, llamaría al método anterior pasando un objeto DateTime como parámetro, por ejemplo:

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

Para obtener más información sobre el constructor DateTime , consulte la página de Microsoft Docs .

Anthony Walsh
fuente
2
@Greg ¿Eso es extraño como var suffix = CreateDateSuffix(new DateTime(2013, 10, 8));devuelve '8th' en mi caso?
Anthony Walsh
1
Si agregara 'th' a la cadena 'ocho' sería incorrecto, pero en este caso, dado que usó el dígito 8, es correcto.
gcochard
El método anterior, tal como está, toma un objeto DateTime y no puedo ver cómo podría instanciarse con algo más que valores numéricos, en este caso, ' 8 ' que representa el día del mes.
Anthony Walsh
En ese caso, es correcto. Si tuviera que, no sé, reemplazar el valor numérico con la representación textual del número, sería incorrecto. Sin embargo, supongo que depende de quien esté reemplazando, saber esto y reemplazar '8t' con 'ocho', o más correctamente, reemplazar '8' con 'eigh'.
gcochard
8

Aquí está la versión extendida que incluye 11, 12 y 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";
Piotr Lewandowski
fuente
y ¿qué hay de "11", "12" y "13"?
sjngm
Debo haberme perdido esto. Lo arreglé arriba.
Piotr Lewandowski
Para su información, si esto fuera necesario para números mayores de ("dd")lo que produciría, usestring.PadLeft()
maxp
@PiotrLewandowski - ¿No eres de Manchester por casualidad? Porque conozco uno de ahí. Demasiado extraño +1 por cierto
Piotr Kula
7

Tomando la respuesta de @ Lazlow a una solución completa, el siguiente es un método de extensión completamente reutilizable, con un ejemplo de uso;

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

Para usar esto, simplemente lo llamaría en un DateTimeobjeto;

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

Que te dará:

Viernes 17 de junio de 2016

Mark Cooper
fuente
5

ACTUALIZAR

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

Ejemplo:
https://dotnetfiddle.net/zXQX7y

Admite:
.NET Core 1.0 y superior
.NET Framework 4.5 y superior


Aquí hay un método de extensión (porque a todos les encantan los métodos de extensión), con la respuesta de Lazlow como base (elegí la de Lazlow porque es fácil de leer).

Funciona igual que el ToString()método normal DateTimecon la excepción de que si el formato contiene un do dd, el sufijo se agregará automáticamente.

/// <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);
}
GFoley83
fuente
1
Sorprendido de que esto no tenga más votos, prefiero el hecho de que sea una extensión. Hace que sea mucho más fácil de usar y posiblemente más legible.
0Neji
2

Creo que esta es una buena solución, que cubre números como el 111, 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;
}
Duncan
fuente
Aunque este es un método de propósito más general, para cualquier número, no solo meses (creo).
Duncan
1

público estático 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);
  }
Robert Peter Bronstein
fuente
1
Esta versión muestra solo el primer dígito de un día, es decir, el 1 de marzo de 2017, donde no quería el nombre del día primero como en una fecha larga y no quería el 01 en lugar del 1
Robert Peter Bronstein
1

Para aquellos que estén felices de usar dependencias externas (en este caso el fantástico Humanizr .net ), es tan simple como

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

Gumzle
fuente
0

Lo hice así, soluciona algunos de los problemas dados en los otros ejemplos.

    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";
        }
    }
rashleighp
fuente
0

Una solución VB barata y alegre:

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
Tony
fuente
0

Por lo que vale, aquí está mi solución final usando las siguientes respuestas

     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"); 
Corbin Spicer
fuente
0

Obtener el sufijo de fecha. (Función estática)

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

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

Manjunath Bilwar
fuente
0

Echa un vistazo a 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"

Inmediatamente después de publicar esto, me di cuenta de que @Gumzle sugirió lo mismo, pero me perdí su publicación porque estaba enterrada en fragmentos de código. Entonces, esta es su respuesta con suficiente código para que alguien (como yo) que se desplaza rápidamente pueda verlo.

Drew Delano
fuente
-2

Otra opción que usa el último carácter de cadena:

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;
}
Jodda
fuente
Gracias AakashM tienes razón, he editado para corregir el error.
Jodda
Ahora se da 1th, 2thy 3th.
AakashM
-4

en la documentación de MSDN no hay ninguna referencia a una cultura que pueda convertir ese 17 en el 17. por lo que debería hacerlo manualmente a través del código subyacente. O crear uno ... podría crear una función que haga eso.

public string CustomToString(this DateTime date)
    {
        string dateAsString = string.empty;
        <here wright your code to convert 17 to 17th>
        return dateAsString;
    }
GxG
fuente