Como você formata o dia do mês para dizer “11”, “21” ou “23” (indicador ordinal)?

Eu sei que isso vai me dar o dia do mês como um número ( 11 , 21 , 23 ):

 SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d"); 

Mas como você formata o dia do mês para include um indicador ordinal , digamos 11th , 21st ou 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"; } } 

A tabela do @kaliatech é legal, mas como a mesma informação é repetida, ela abre a chance de um bug. Esse bug realmente existe na tabela para 7tn , 17tn e 27tn (esse bug pode ser corrigido com o passar do tempo devido à natureza fluida do StackOverflow, portanto, verifique o histórico da versão na resposta para ver o erro).

Não há nada no JDK para fazer isso.

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

Ou usando o Calendário:

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

Por comentários de @ thorbjørn-ravn-andersen, uma tabela como essa pode ser útil ao 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)]; } 

A questão é pouco antiga. Como esta questão é muito barulhenta, então postar o que eu resolvi com o método estático como um utilitário. Basta copiar, colar e usar!

  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 testes purose

Exemplo: chamando do 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)); } 

Saída:

 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 

Se você tentar estar ciente do i18n, a solução se torna ainda mais complicada.

O problema é que em outras línguas o sufixo pode depender não apenas do número em si, mas também do substantivo que conta. Por exemplo, em russo, seria “2-ой день”, mas “2-a-неделя” (significam “2º dia”, mas “segunda semana”). Isso não se aplica se formatarmos apenas alguns dias, mas em um caso um pouco mais genérico, você deve estar ciente da complexidade.

Eu acho que uma boa solução (eu não tive tempo para realmente implementar) seria estender SimpleDateFormetter para aplicar MessageFormat Local-aware antes de passar para a class pai. Dessa forma, você seria capaz de suportar, digamos, os formatos de março% M para obter “3-rd”,% MM para obter “03-rd” e% MMM para obter “terceiro”. De fora desta class parece regular SimpleDateFormatter, mas suporta mais formatos. Além disso, se esse padrão fosse por engano aplicado pelo SimpleDateFormetter regular, o resultado seria formatado incorretamente, mas ainda assim legível.

Muitos dos exemplos aqui não funcionarão para 11, 12, 13. Isso é mais genérico e funcionará para todos os 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"; } 

Não posso ficar satisfeito com as respostas que pedem uma solução somente em inglês, baseada em formatos manuais. Eu tenho procurado por uma solução adequada por um tempo agora e finalmente encontrei.

Você deve estar usando RuleBasedNumberFormat . Ele funciona perfeitamente e é respeitoso com o Locale.

Existe uma maneira mais simples e segura de fazer isso. A function que você precisará usar é getDateFromDateString (dateString); Basicamente remove o st / nd / rd / th de uma string de data e simplesmente o analisa. Você pode mudar o seu SimpleDateFormat para qualquer coisa e isso vai 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; 

}

O único problema com a solução fornecida por Greg é que ela não considera o número maior que 100 com os números “teen” terminando. Por exemplo, 111 deve ser 111º, não 111º. Esta é minha solução:

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

Eu gostaria de contribuir com a resposta moderna. A class SimpleDateFormat foi OK para usar quando a pergunta foi feita há quase 8 anos, mas você deve evitá-la agora, pois ela não é apenas muito desatualizada, mas também notoriamente problemática. Use java.time vez disso:

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

Correndo este trecho apenas agora eu tenho

23

Um dos muitos resources do java.time é que é direto e confiável para obter o dia do mês como um int , que obviamente é necessário para escolher o sufixo correto da tabela.

Eu recomendo que você escreva um teste de unidade também.

Link: tutorial do Oracle: Date Time explicando como usar java.time .

No kotlin você pode usar assim

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

definido assim

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

Se você precisa disso no Android, você pode verificar essa resposta

É uma solução internacionalizada, no entanto. E você não precisa reinventar a bicicleta;)

A seguir, uma resposta mais eficiente à pergunta, em vez de codificar o estilo.

Para alterar o dia para o número ordinal, você precisa usar o seguinte sufixo .

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

Encontre minha resposta completa nesta pergunta.

O método a seguir pode ser usado para obter a string formatada da data que é passada para ela. Ele formata a data para dizer primeiro, segundo, terceiro, quarto .. usando SimpleDateFormat em Java. Por exemplo: – 1º de setembro 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"; } }