Come si fa a formattare il giorno del mese per dire “11”, “21” o in “23” (indicatore ordinale)?

StackOverflow https://stackoverflow.com/questions/4011075

Domanda

So che questo mi dia il giorno del mese come un numero (11, 21, 23):

SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");

Ma come si fa a formattare il giorno del mese di includere un indicatore ordinale, dire 11th, 21st o 23rd?

È stato utile?

Soluzione

// https://github.com/google/guava
import static com.google.common.base.Preconditions.*;

String getDayOfMonthSuffix(final int n) {
    checkArgument(n >= 1 && n <= 31, "illegal day of month: " + n);
    if (n >= 11 && n <= 13) {
        return "th";
    }
    switch (n % 10) {
        case 1:  return "st";
        case 2:  return "nd";
        case 3:  return "rd";
        default: return "th";
    }
}

La tavola da @kaliatech è bello, ma dal momento che la stessa informazione viene ripetuta, si apre la possibilità di un bug. Tale problema esiste realmente nella tabella per 7tn, 17tn, e 27tn (questo errore potrebbe avere fissato col passare del tempo a causa della natura fluida StackOverflow, in modo da verificare la cronologia delle versioni sulla risposta per vedere l'errore).

Altri suggerimenti

Non c'è nulla in JDK per fare questo.

  static String[] suffixes =
  //    0     1     2     3     4     5     6     7     8     9
     { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th",
  //    10    11    12    13    14    15    16    17    18    19
       "th", "th", "th", "th", "th", "th", "th", "th", "th", "th",
  //    20    21    22    23    24    25    26    27    28    29
       "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th",
  //    30    31
       "th", "st" };

 Date date = new Date();
 SimpleDateFormat formatDayOfMonth  = new SimpleDateFormat("d");
 int day = Integer.parseInt(formatDateOfMonth.format(date));
 String dayStr = day + suffixes[day];

o utilizzando Calendario:

 Calendar c = Calendar.getInstance();
 c.setTime(date);
 int day = c.get(Calendar.DAY_OF_MONTH);
 String dayStr = day + suffixes[day];

Per commenti da @ Thorbjørn-Ravn Andersen, una tabella come questa può essere utile quando la localizzazione:

  static String[] suffixes =
     {  "0th",  "1st",  "2nd",  "3rd",  "4th",  "5th",  "6th",  "7th",  "8th",  "9th",
       "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th",
       "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th",
       "30th", "31st" };
private String getCurrentDateInSpecificFormat(Calendar currentCalDate) {
    String dayNumberSuffix = getDayNumberSuffix(currentCalDate.get(Calendar.DAY_OF_MONTH));
    DateFormat dateFormat = new SimpleDateFormat(" d'" + dayNumberSuffix + "' MMMM yyyy");
    return dateFormat.format(currentCalDate.getTime());
}

private String getDayNumberSuffix(int day) {
    if (day >= 11 && day <= 13) {
        return "th";
    }
    switch (day % 10) {
    case 1:
        return "st";
    case 2:
        return "nd";
    case 3:
        return "rd";
    default:
        return "th";
    }
}

La domanda è po 'vecchio. Poiché questa domanda è molto rumoroso quindi distacco quello che ho fatto risolto con metodo statico come un util. Basta copiare, incollare e usarlo!

 public static String getFormattedDate(Date date){
            Calendar cal=Calendar.getInstance();
            cal.setTime(date);
            //2nd of march 2015
            int day=cal.get(Calendar.DATE);

            if(!((day>10) && (day<19)))
            switch (day % 10) {
            case 1:  
                return new SimpleDateFormat("d'st' 'of' MMMM yyyy").format(date);
            case 2:  
                return new SimpleDateFormat("d'nd' 'of' MMMM yyyy").format(date);
            case 3:  
                return new SimpleDateFormat("d'rd' 'of' MMMM yyyy").format(date);
            default: 
                return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
        }
        return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
    }

Per testare PUROSE

Esempio:! Chiamando dal metodo main

Date date = new Date();
        Calendar cal=Calendar.getInstance();
        cal.setTime(date);
        for(int i=0;i<32;i++){
          System.out.println(getFormattedDate(cal.getTime()));
          cal.set(Calendar.DATE,(cal.getTime().getDate()+1));
        }

Output:

22nd of February 2018
23rd of February 2018
24th of February 2018
25th of February 2018
26th of February 2018
27th of February 2018
28th of February 2018
1st of March 2018
2nd of March 2018
3rd of March 2018
4th of March 2018
5th of March 2018
6th of March 2018
7th of March 2018
8th of March 2018
9th of March 2018
10th of March 2018
11th of March 2018
12th of March 2018
13th of March 2018
14th of March 2018
15th of March 2018
16th of March 2018
17th of March 2018
18th of March 2018
19th of March 2018
20th of March 2018
21st of March 2018
22nd of March 2018
23rd of March 2018
24th of March 2018
25th of March 2018
String ordinal(int num)
{
    String[] suffix = {"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"};
    int m = num % 100;
    return String.valueOf(num) + suffix[(m > 3 && m < 21) ? 0 : (m % 10)];
}

Vorrei contribuire con la risposta più moderna.Il SimpleDateFormat la classe era OK per l'uso, quando la domanda è stato chiesto 8 anni fa, ma si dovrebbe evitare di oggi che non è solo lunga superate, ma anche notoriamente problematico.Utilizzare java.time invece.

Modifica

DateTimeFormatterBuilder.appendText(TemporalField, Map<Long, String>) è grande per questo scopo.Che costruire un programma di impaginazione che fa il lavoro per noi:

    Map<Long, String> ordinalNumbers = new HashMap<>(42);
    ordinalNumbers.put(1L, "1st");
    ordinalNumbers.put(2L, "2nd");
    ordinalNumbers.put(3L, "3rd");
    ordinalNumbers.put(21L, "21st");
    ordinalNumbers.put(22L, "22nd");
    ordinalNumbers.put(23L, "23rd");
    ordinalNumbers.put(31L, "31st");
    for (long d = 1; d <= 31; d++) {
        ordinalNumbers.putIfAbsent(d, "" + d + "th");
    }

    DateTimeFormatter dayOfMonthFormatter = new DateTimeFormatterBuilder()
            .appendText(ChronoField.DAY_OF_MONTH, ordinalNumbers)
            .appendPattern(" MMMM")
            .toFormatter();

    LocalDate date = LocalDate.of(2018, Month.AUGUST, 30);
    for (int i = 0; i < 6; i++) {
        System.out.println(date.format(dayOfMonthFormatter));
        date = date.plusDays(1);
    }

L'uscita da questo frammento di codice è:

30th August
31st August
1st September
2nd September
3rd September
4th September

Vecchia risposta

Questo codice è più breve, ma IMHO non così elegante.

    // ordinal indicators by numbers (1-based, cell 0 is wasted)
    String[] ordinalIndicators = new String[31 + 1];
    Arrays.fill(ordinalIndicators, 1, ordinalIndicators.length, "th");
    ordinalIndicators[1] = ordinalIndicators[21] = ordinalIndicators[31] = "st";
    ordinalIndicators[2] = ordinalIndicators[22] = "nd";
    ordinalIndicators[3] = ordinalIndicators[23] = "rd";

    DateTimeFormatter dayOfMonthFormatter = DateTimeFormatter.ofPattern("d");

    LocalDate today = LocalDate.now(ZoneId.of("America/Menominee")).plusWeeks(1);
    System.out.println(today.format(dayOfMonthFormatter) 
                        + ordinalIndicators[today.getDayOfMonth()]);

L'esecuzione di questo frammento solo ora ho capito

23

Una delle molte caratteristiche di java.time è che è semplice e affidabile per ottenere il giorno del mese di int, che è, ovviamente, necessario per la raccolta di destra, il suffisso da tavolo.

Mi consiglia di scrivere una unità di prova troppo.

PS Un simile programma di formattazione può essere utilizzato anche per l'analisi una data stringa contenente i numeri ordinali come 1st, 2nd, etc.Che è stato fatto in a questa domanda: Java - Analisi data opzionale secondi.

Link: Oracle tutorial:Data Ora spiegare come si usa java.time.

Se si tenta di essere a conoscenza di i18n soluzione si complicano ulteriormente.

Il problema è che in altre lingue il suffisso può dipendere non solo dal numero in sé, ma anche sul sostantivo che conta. Per esempio in russo sarebbe "2-ой день", ma "2-ая неделя" (questi media "2 ° giorno", ma "2 ° settimana"). Questo non è applicabile se ci formattazione solo pochi giorni, ma in un po 'più generico caso si dovrebbe essere consapevoli della complessità.

Credo che bella soluzione (non ho avuto il tempo di applicare concretamente) sarebbe quella di estendere SimpleDateFormetter applicare MessageFormat Locale-consapevoli prima di passare alla classe padre. In questo modo si sarebbe in grado di sostenere diciamo per marzo formati% M per ottenere "3-rd",% MM per ottenere "03-rd" e% MMM per ottenere "terzo". Dall'esterno questo sembra di classe come SimpleDateFormatter regolare, ma supporta più formati. Anche se questo modello sarebbe per errore applicato dalla SimpleDateFormetter regolare il risultato sarebbe stato formattato in modo errato, ma ancora leggibile.

Molti degli esempi qui non funzionerà per 11, 12, 13. Questo è più generico e funzionerà per tutti i casi.

switch (date) {
                case 1:
                case 21:
                case 31:
                    return "" + date + "st";

                case 2:
                case 22:
                    return "" + date + "nd";

                case 3:
                case 23:
                    return "" + date + "rd";

                default:
                    return "" + date + "th";
}

Non posso essere soddisfatta dalle risposte che chiedono un inglese unica soluzione basata su formati manuali. Sono stato alla ricerca di una soluzione adeguata per un po 'e alla fine ho trovato.

Si deve usare RuleBasedNumberFormat . Funziona perfettamente ed è rispettoso del Locale.

C'è un modo più semplice e sicuro di fare questo. La funzione è necessario l'uso è getDateFromDateString (dateString); Rimuove fondamentalmente la st / ° / ° / ° fuori di una stringa di data e semplicemente lo analizza. È possibile modificare la SimpleDateFormat a nulla e questo funzionerà.

public static final SimpleDateFormat sdf = new SimpleDateFormat("d");
public static final Pattern p = Pattern.compile("([0-9]+)(st|nd|rd|th)");

private static Date getDateFromDateString(String dateString) throws ParseException {
     return sdf.parse(deleteOrdinal(dateString));
}

private static String deleteOrdinal(String dateString) {
    Matcher m = p.matcher(dateString);
    while (m.find()) {
        dateString = dateString.replaceAll(Matcher.quoteReplacement(m.group(0)), m.group(1));
    }
    return dateString;

}

L'unico problema con la soluzione fornita da Greg è che non tiene conto di numero superiore a 100 con i numeri "adolescenti" terminano. Ad esempio, 111 dovrebbe essere 111 °, non 111a. Questa è la mia soluzione:

/**
 * Return ordinal suffix (e.g. 'st', 'nd', 'rd', or 'th') for a given number
 * 
 * @param value
 *           a number
 * @return Ordinal suffix for the given number
 */
public static String getOrdinalSuffix( int value )
{
    int hunRem = value % 100;
    int tenRem = value % 10;

    if ( hunRem - tenRem == 10 )
    {
        return "th";
    }
    switch ( tenRem )
    {
    case 1:
        return "st";
    case 2:
        return "nd";
    case 3:
        return "rd";
    default:
        return "th";
    }
}

Ecco un approccio che aggiorna un modello DateTimeFormatter con il corretto il suffisso letterale se trova la d'00' modello, per esempio per il giorno del mese 1 sarebbe sostituito con d'st'. Una volta che il modello è stato aggiornato può quindi solo essere immessa nella DateTimeFormatter per fare il resto.

private static String[] suffixes = {"th", "st", "nd", "rd"};

private static String updatePatternWithDayOfMonthSuffix(TemporalAccessor temporal, String pattern) {
    String newPattern = pattern;
    // Check for pattern `d'00'`.
    if (pattern.matches(".*[d]'00'.*")) {
        int dayOfMonth = temporal.get(ChronoField.DAY_OF_MONTH);
        int relevantDigits = dayOfMonth < 30 ? dayOfMonth % 20 : dayOfMonth % 30;
        String suffix = suffixes[relevantDigits <= 3 ? relevantDigits : 0];
        newPattern = pattern.replaceAll("[d]'00'", "d'" + suffix + "'");
    }

    return newPattern;
}

Si richiede che il modello originale viene aggiornato appena prima di ogni chiamata la formattazione, per esempio.

public static String format(TemporalAccessor temporal, String pattern) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(updatePatternWithDayOfMonthSuffix(temporal, pattern));
    return formatter.format(temporal);
}

Quindi questo è utile se il modello di formattazione è definito al di fuori del codice Java, per esempio un modello, dove come se si può definire il pattern in Java allora la risposta da @ OleV.V. potrebbe essere più appropriato

ho scritto la mia auto un metodo di supporto per ottenere i modelli per questo.

public static String getPattern(int month) {
    String first = "MMMM dd";
    String last = ", yyyy";
    String pos = (month == 1 || month == 21 || month == 31) ? "'st'" : (month == 2 || month == 22) ? "'nd'" : (month == 3 || month == 23) ? "'rd'" : "'th'";
    return first + pos + last;
}

e poi possiamo chiamare come

LocalDate localDate = LocalDate.now();//For reference
int month = localDate.getDayOfMonth();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(getPattern(month));
String date = localDate.format(formatter);
System.out.println(date);

l'uscita è

December 12th, 2018

In Kotlin è possibile utilizzare in questo modo

fun changeDateFormats(currentFormat: String, dateString: String): String {
        var result = ""
        try {
            val formatterOld = SimpleDateFormat(currentFormat, Locale.getDefault())
            formatterOld.timeZone = TimeZone.getTimeZone("UTC")

            var date: Date? = null

            date = formatterOld.parse(dateString)

            val dayFormate = SimpleDateFormat("d", Locale.getDefault())
            var day = dayFormate.format(date)

            val formatterNew = SimpleDateFormat("hh:mm a, d'" + getDayOfMonthSuffix(day.toInt()) + "' MMM yy", Locale.getDefault())

            if (date != null) {
                result = formatterNew.format(date)
            }

        } catch (e: ParseException) {
            e.printStackTrace()
            return dateString
        }

        return result
    }


    private fun getDayOfMonthSuffix(n: Int): String {
        if (n in 11..13) {
            return "th"
        }
        when (n % 10) {
            1 -> return "st"
            2 -> return "nd"
            3 -> return "rd"
            else -> return "th"
        }
    }

set come questo

  txt_chat_time_me.text = changeDateFormats("SERVER_DATE", "DATE")

Se avete bisogno di questo su Android è possibile controllare questa risposta

E 'internazionalizzato soluzione, però. E non è necessario reinventare la bicicletta;)

Il seguente metodo può essere utilizzato per ottenere la stringa formattata della data che viene passato ad esso. Sarà formattare la data di dire 1 °, 2 °, 3 °, 4 ° .. utilizzando SimpleDateFormat in Java. ad esempio: - 1 settembre 2015

public String getFormattedDate(Date date){
            Calendar cal=Calendar.getInstance();
            cal.setTime(date);
            //2nd of march 2015
            int day=cal.get(Calendar.DATE);

            switch (day % 10) {
            case 1:  
                return new SimpleDateFormat("d'st' 'of' MMMM yyyy").format(date);
            case 2:  
                return new SimpleDateFormat("d'nd' 'of' MMMM yyyy").format(date);
            case 3:  
                return new SimpleDateFormat("d'rd' 'of' MMMM yyyy").format(date);
            default: 
                return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
        }

La seguente è una risposta più efficace alla domanda piuttosto che hard-codifica lo stile.

Per cambiare il giorno per numero ordinale è necessario utilizzare il seguente suffisso .

DD +     TH = DDTH  result >>>> 4TH

OR to spell the number add SP to the format

DD + SPTH = DDSPTH   result >>> FOURTH

Conoscere la mia risposta completato nel questa domanda .

public String getDaySuffix(int inDay)
{
  String s = String.valueOf(inDay);

  if (s.endsWith("1"))
  {
    return "st";
  }
  else if (s.endsWith("2"))
  {
    return "nd";
  }
  else if (s.endsWith("3"))
  {
    return "rd";
  }
  else
  {
    return "th";
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top