¿Cómo formatea el día del mes para decir “11 °”, “21 °” o “23 °” (indicador ordinal)?

Sé que esto me dará el día del mes como número ( 11 , 21 , 23 ):

 SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d"); 

¿Pero cómo formatear el día del mes para incluir un indicador ordinal , por ejemplo, 11th , 21st o 23rd ?

 // 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 tabla de @kaliatech es agradable, pero dado que se repite la misma información, abre la posibilidad de un error. Tal error en realidad existe en la tabla para 7tn , 17tn y 27tn (este error podría arreglarse a medida que pase el tiempo debido a la naturaleza fluida de StackOverflow, así que verifique el historial de versiones en la respuesta para ver el error).

No hay nada en JDK para hacer esto.

  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 usando el calendario:

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

Según los comentarios de @ thorbjørn-ravn-andersen, una tabla como esta puede ser útil al localizar:

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

La pregunta es un poco vieja. Como esta pregunta es muy ruidosa, publicando lo que hice resuelto con el método estático como utilidad. ¡Solo copie, pegue y use!

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

Para probar purose

Ejemplo: llamarlo desde el método principal!

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

Salida:

 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 

Si intentas ser consciente de i18n, la solución se complica aún más.

El problema es que en otros idiomas el sufijo puede depender no solo del número en sí mismo, sino también del sustantivo que cuenta. Por ejemplo, en ruso sería “2-ой день”, pero “2-aя неделя” (estos significan “2 ° día”, pero “2 ° semana”). Esto no se aplica si formateamos solo días, pero en un caso un poco más genérico debe ser consciente de la complejidad.

Creo que una buena solución (no tuve tiempo para implementarla realmente) sería extender SimpleDateFormetter para aplicar MessageFormat Local-aware antes de pasar a la clase padre. De esta forma, podría admitir, por ejemplo, los formatos de marzo% M para obtener “3-rd”,% MM para obtener “03-rd” y% MMM para obtener “tercero”. Desde fuera, esta clase se ve como SimpleDateFormatter normal, pero admite más formatos. Además, si este patrón fuera por error aplicado por SimpleDateFormetter regular, el resultado sería formateado incorrectamente, pero aún legible.

Muchos de los ejemplos aquí no funcionarán para 11, 12, 13. Esto es más genérico y funcionará para todos los casos.

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

No puedo estar satisfecho con las respuestas que requieren una solución solo en inglés basada en formatos manuales. He estado buscando una solución adecuada por un tiempo y finalmente la encontré.

Debería usar RuleBasedNumberFormat . Funciona perfectamente y es respetuoso de la configuración regional.

Hay una manera más simple y segura de hacer esto. La función que necesitará usar es getDateFromDateString (dateString); Básicamente elimina el st / nd / rd / th de una cadena de fecha y simplemente lo analiza. Puede cambiar su SimpleDateFormat a cualquier cosa y esto funcionará.

 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; 

}

El único problema con la solución provista por Greg es que no cuenta para un número mayor a 100 con el final de los números “adolescentes”. Por ejemplo, 111 debería ser 111º, no 111º. Esta es mi solución:

 /** * Return ordinal suffix (eg '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"; } } 

Me gustaría contribuir con la respuesta moderna. La clase SimpleDateFormat estaba bien para usar cuando se formuló la pregunta hace casi 8 años, pero debe evitarla ahora, ya que no solo está desactualizada hace tiempo, sino que también es notoriamente problemática. Use java.time en java.time lugar:

  // 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()]); 

Ejecutando este fragmento justo ahora tengo

23 °

Una de las muchas características de java.time es que es sencillo y confiable obtener el día del mes como int , lo que obviamente es necesario para elegir el sufijo correcto de la tabla.

Te recomiendo que también escribas una prueba unitaria.

Enlace: tutorial de Oracle: Fecha y hora explicando cómo usar java.time .

En kotlin puedes usar esto

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

establecer de esta manera

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

Si necesita esto en Android puede ver esta respuesta

Sin embargo, es una solución internacionalizada. Y no necesita reinventar la bicicleta;)

La siguiente es una respuesta más eficiente a la pregunta que un estilo de encoding difícil.

Para cambiar el día al número ordinal, necesita usar el siguiente sufijo .

 DD + TH = DDTH result >>>> 4TH OR to spell the number add SP to the format DD + SPTH = DDSPTH result >>> FOURTH 

Encuentra mi respuesta completa en esta pregunta.

El siguiente método se puede usar para obtener la cadena formateada de la fecha que se le pasa. Formateará la fecha para decir 1st, 2nd, 3rd, 4th .. usando SimpleDateFormat en Java. por ejemplo: – 1 de septiembre de 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); } 
 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"; } }