كيف يمكنك تنسيق يوم الشهر لتقول "11" أو "21" أو "23" (المؤشر الترتيبي)؟

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

سؤال

أعلم أن هذا سيعطيني يوم الشهر كرقم (11, 21, 23):

SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");

ولكن كيف يمكنك تنسيق يوم الشهر لتضمين مؤشر ترتيبي, ، قل 11th, 21st أو 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";
    }
}

يعد الجدول من Kaliatech لطيفًا ، ولكن نظرًا لأن المعلومات نفسها تتكرر ، فإنها تفتح فرصة لخطأ. مثل هذا الخطأ موجود بالفعل في الجدول ل 7tn, 17tn, ، و 27tn (قد يتم إصلاح هذا الخطأ مع مرور الوقت بسبب الطبيعة السائلة لـ StackOverflow ، لذا تحقق تاريخ الإصدار على الإجابة لرؤية الخطأ).

نصائح أخرى

لا يوجد شيء في 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];

أو استخدام التقويم:

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

لكل تعليقات من قبل @Thorbjørn-Ravn-Andersen ، يمكن أن يكون جدول مثل هذا مفيدًا عند التوطين:

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

السؤال قديم صغير. نظرًا لأن هذا السؤال صاخب للغاية ، لذا فإن نشر ما قمت به بالطريقة الثابتة كطريقة. فقط نسخ ولصق واستخدامه!

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

لاختبار parose

مثال: تسميها من الطريقة الرئيسية!

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

انتاج:

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

أود أن أساهم في الإجابة الحديثة. ال SimpleDateFormat كان الفصل على ما يرام لاستخدامه عندما تم طرح السؤال قبل 8 سنوات ، ولكن يجب عليك تجنب ذلك الآن لأنه ليس طويلًا فقط ، ولكن أيضًا مزعجًا. يستخدم java.time في حين أن.

تعديل

DateTimeFormatterBuilder.appendText(TemporalField, Map<Long, String>) رائع لهذا الغرض. باستخدامه ، نقوم ببناء تنسيق يقوم بالعمل بالنسبة لنا:

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

الإخراج من هذا المقتطف هو:

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

إجابة قديمة

هذا الرمز أقصر ، ولكن IMHO ليس أنيقًا جدًا.

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

تشغيل هذا المقتطف الآن حصلت عليه

23

واحدة من العديد من ميزات java.time هل من السهل وموثوق أن تحصل على يوم الشهر ك int, ، والتي من الواضح أنها مطلوبة لاختيار اللاحقة الصحيحة من الطاولة.

أنصحك بكتابة اختبار الوحدة أيضًا.

ملاحظة يمكن أيضًا استخدام تنسيق مماثل ل تفسير سلسلة تاريخ تحتوي على أرقام ترتيبية مثل 1st, 2nd, ، إلخ. تم ذلك في هذا السؤال: جافا - تاريخ التحليل بثواني اختيارية.

وصلة: تعليمي أوراكل: وقت التاريخ شرح كيفية الاستخدام java.time.

إذا حاولت أن تكون على دراية بـ I18N ، يصبح الحل أكثر تعقيدًا.

المشكلة هي أنه في اللغات الأخرى ، قد تعتمد اللاحقة على العدد نفسه فحسب ، ولكن أيضًا على الاسم الذي يهمه. على سبيل المثال ، سيكون "2-й день" ، ولكن "2-а н н اير ، (هذه تعني" اليوم الثاني "، ولكن" الأسبوع الثاني "). لا يتم تطبيق هذا إذا قمنا بتنسيق أيام فقط ، ولكن في حالة عامة أكثر قليلاً ، يجب أن تكون على دراية بالتعقيد.

أعتقد أن الحل الجميل (لم يكن لدي وقت للتنفيذ فعليًا) هو تمديد SimpleDateFormetter لتطبيق Messageformat-Quarting قبل الانتقال إلى فئة الأصل. وبهذه الطريقة ، ستتمكن من دعم Let Let Salle for March Formats ٪ M للحصول على "3-RD" و ٪ MM للحصول على "03-RD" و ٪ MMM للحصول على "الثالث". من خارج هذه الفئة يبدو وكأنه التبسيط المنتظم ، ولكنه يدعم المزيد من التنسيقات. وأيضًا إذا كان هذا النمط سيكون عن طريق الخطأ الذي يتم تطبيقه بواسطة SimpledAteFormetter العادي ، فسيتم تنسيق النتيجة بشكل غير صحيح ، ولكن لا يزال قابلاً للقراءة.

العديد من الأمثلة هنا لن تعمل لمدة 11 ، 12 ، 13. هذا أكثر عامة وسيعمل في كل الحالات.

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

لا يمكنني أن أكون راضيًا عن الإجابات التي تدعو إلى حل اللغة الإنجليزية فقط على أساس التنسيقات اليدوية. لقد كنت أبحث عن حل مناسب لفترة من الوقت الآن ووجدته أخيرًا.

يجب أن تستخدم RuleBasedNumberformat. إنه يعمل بشكل مثالي ويحترم اللغة.

هناك طريقة أبسط ومتأكد للقيام بذلك. الوظيفة التي ستحتاجها إلى استخدامها هي getDateFromDatestring (البيانات) ؛ إنه يزيل بشكل أساسي ST/ND/RD/TH من سلسلة التاريخ ويقوم ببساطة بتحليلها. يمكنك تغيير SimpleDateFormat إلى أي شيء وسيعمل هذا.

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;

}

فقط المشكلة مع الحل الذي توفره Greg هو أنه لا يمثل رقمًا أكبر من 100 مع انتهاء أرقام "المراهقين". على سبيل المثال ، يجب أن يكون 111 111 ، وليس 111. هذا هو الحل:

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

فيما يلي نهج يقوم بتحديث نمط DateTimeFormatter مع اللاحقة الصحيح الحرفي إذا وجد النمط d'00', ، على سبيل المثال ليوم الشهر الأول ، سيتم استبداله بـ d'st'. بمجرد تحديث النمط ، يمكن بعد ذلك تغذية DateTimeFormatter للقيام بالباقي.

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

يتطلب الأمر تحديث النمط الأصلي قبل كل مكالمة تنسيق ، على سبيل المثال

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

لذلك يكون هذا مفيدًا إذا تم تعريف نمط التنسيق خارج رمز Java ، على سبيل المثال قالب ، حيث يمكنك تحديد النمط في Java ثم الإجابة بواسطة @Olev.v. قد يكون أكثر ملاءمة

كتبت نفسي طريقة مساعد للحصول على أنماط لهذا.

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

وبعد ذلك يمكننا أن نسميها باسم

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

الإخراج هو

December 12th, 2018

في Kotlin يمكنك استخدام مثل هذا

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

اضبط هكذا

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

إذا كنت بحاجة إلى ذلك على Android ، يمكنك التحقق من ذلك هذا الجواب

إنه حل دولي ، رغم ذلك. ولا تحتاج إلى إعادة اختراع الدراجة ؛)

يمكن استخدام الطريقة التالية للحصول على السلسلة المنسقة من التاريخ الذي يتم تمريره إليه. سيؤدي إلى تنسيق التاريخ ليقول الأول والثاني والثالث والرابع .. باستخدام SimpleDateFormat في Java. على سبيل المثال:- الأول من سبتمبر 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);
        }

فيما يلي إجابة أكثر كفاءة على السؤال بدلاً من ترميز النمط.

لتغيير اليوم إلى الرقم الترتيبي ، تحتاج إلى استخدام ما يلي لاحقة.

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

OR to spell the number add SP to the format

DD + SPTH = DDSPTH   result >>> FOURTH

ابحث عن إجابتي المكتملة في هذه سؤال.

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";
  }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top