Comment formater-vous le jour du mois pour dire « 11 », « 21 » ou « 23 » (indicateur ordinal)?

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

Question

Je sais que cela va me donner le jour du mois en nombre (11, 21, 23):

SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");

Mais comment formater-vous le jour du mois d'inclure un indicateur ordinal , dire 11th, 21st ou 23rd?

Était-ce utile?

La solution

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

Le tableau de @kaliatech est agréable, mais étant donné la même information est répétée, il ouvre la possibilité d'un bug. Un tel bug existe réellement dans la table pour 7tn, 17tn et 27tn (ce bug pourrait se fixe au fil du temps en raison de la nature fluide de StackOverflow, afin de vérifier l'historique de version sur la réponse pour voir l'erreur).

Autres conseils

Il n'y a rien à faire pour JDK.

  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 en utilisant le calendrier:

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

Par commentaires par @ Thorbjørn-ravn-andersen, une table, comme cela peut être utile lorsque localisant:

  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 question est peu vieux. Cette question est très bruyante affichant donc ce que je ne résolu avec la méthode statique comme util. Il suffit de copier, coller et de l'utiliser!

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

Pour les tests purose

Exemple: appeler de méthode principale

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

Sortie:

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

Je voudrais contribuer la réponse moderne. La classe SimpleDateFormat était correct d'utiliser quand on a posé la question il y a 8 ans, mais vous devriez éviter maintenant car il est non seulement dépassée depuis longtemps, mais aussi notoirement gênants. Utilisez plutôt java.time.

Modifier

DateTimeFormatterBuilder.appendText(TemporalField, Map<Long, String>) est grande à cet effet. Son utilisation nous construisons un formatter qui fait le travail pour nous:

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

La sortie de cet extrait est:

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

Vieille réponse

Ce code est plus court, mais à mon humble avis pas si élégant.

    // 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'exécution de ce bout je viens juste eu

  

23

L'une des nombreuses caractéristiques de java.time est qu'il est simple et fiable pour obtenir le jour du mois comme int, ce qui est évidemment nécessaire pour choisir le suffixe droite de la table.

Je vous recommande d'écrire un test unitaire aussi.

PS Un formatter similaire peut également être utilisé pour l'analyse syntaxique une chaîne de date contenant des nombres ordinaux comme 1st, 2nd, etc. Cela a été fait dans cette question:. Java - avec la date Parse secondes en option

: tutoriel Oracle: Date Heure expliquant comment utiliser java.time.

Si vous essayez d'être au courant de la solution i18n obtenir encore plus compliquée.

Le problème est que dans d'autres langues, le suffixe peut dépendre non seulement sur le nombre lui-même, mais aussi sur le nom qu'il compte. Par exemple, en russe, il serait « 2-ой день », mais « 2-ая неделя » (ceux-ci signifient « 2ème jour », mais « 2ème semaine »). Ceci est pas applicable si l'on formatage jours seulement, mais dans un peu plus de cas générique, vous devriez être conscient de la complexité.

Je pense que la solution agréable (je ne l'ai pas eu le temps de mettre en œuvre effectivement) serait d'étendre SimpleDateFormetter à appliquer MessageFormat conscient de la localisation avant de passer à la classe parente. De cette façon, vous seriez en mesure de soutenir laisser dire pour les formats% M Mars pour obtenir « 3-ème », MM% pour obtenir « 03-ème » et% MMM pour obtenir « troisième ». De l'extérieur de cette classe ressemble SimpleDateFormatter régulière, mais supporte plus de formats. Aussi, si ce modèle serait par erreur appliquée par SimpleDateFormetter régulière le résultat serait mal formaté, mais toujours lisible.

La plupart des exemples ici ne fonctionnera pas pour 11, 12, 13. Ceci est plus générique et fonctionnera pour tous les cas.

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

Je ne peux pas être satisfait par les réponses appelant à une solution en anglais uniquement basé sur les formats manuels. Je cherchais une solution appropriée pour un certain temps maintenant et j'ai finalement trouvé.

Vous devez utiliser RuleBasedNumberFormat . Il fonctionne parfaitement et il est respectueux de l'environnement local.

Il y a une façon simple et sûre de le faire. La fonction que vous aurez besoin d'utiliser est getDateFromDateString (dateString); Il supprime essentiellement la st / e / e / e au large d'une chaîne de date et parse simplement. Vous pouvez changer votre SimpleDateFormat à rien et cela fonctionne.

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;

}

Le seul problème avec la solution fournie par Greg est qu'il ne tient pas compte de nombre supérieur à 100 avec les chiffres « adolescents » qui se terminent. Par exemple, 111 doit être 111e, pas 111st. Ceci est ma solution:

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

Voici une approche qui met à jour un modèle DateTimeFormatter avec le suffixe correct littérale si elle trouve le modèle d'00', par exemple pour le jour du mois 1, il serait remplacé par d'st'. Une fois que le modèle a été mis à jour, il peut alors être simplement introduit dans le DateTimeFormatter pour faire le reste.

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

Il ne nécessite que le modèle original est mis à jour juste avant chaque appel de mise en forme, par exemple.

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

Alors ce qui est utile si le motif de mise en forme est définie en dehors du code Java, par exemple un modèle, alors que si vous pouvez définir le modèle en Java alors la réponse par @ OleV.V. pourrait être plus approprié

J'ai écrit moi-même une méthode d'assistance pour obtenir des motifs pour cela.

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

et on peut l'appeler comme

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

la sortie est

December 12th, 2018

Dans Kotlin vous pouvez utiliser comme ceci

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

ensemble comme celui-ci

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

Si vous avez besoin de ce sur Android vous pouvez vérifier cette réponse

Il est internationalisé solution, cependant. Et vous n'avez pas besoin de réinventer la bicyclette;)

La méthode suivante peut être utilisée pour obtenir la chaîne formatée de la date qui est passé à elle. Il va formater la date à dire 1er, 2ème, 3ème, 4ème .. en utilisant SimpleDateFormat en Java. par exemple: - le 1 Septembre ici à 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);
        }

Ce qui suit est une réponse plus efficace à la question plutôt que de coder en dur le style.

Pour changer le jour au numéro ordinal vous devez utiliser les éléments suivants suffixe .

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

OR to spell the number add SP to the format

DD + SPTH = DDSPTH   result >>> FOURTH

Trouver ma réponse achevée en cette question .

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";
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top