web-dev-qa-db-ja.com

「11日」、「21日」、または「23日」(序数インジケータ)と言うように月の日付をどのようにフォーマットしますか?

これにより、月の日が数字(112123)で得られます。

SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");

しかし、 ordinal indicator 、たとえば11th21stまたは23rdを含めるように、どのように日付をフォーマットしますか?

128
Ken Hume
// 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の表は素晴らしいですが、同じ情報が繰り返されるため、バグの可能性が開かれます。このようなバグは、実際に7tn17tn、および27tnのテーブルに存在します(このバグはStackOverflowの流動的な性質のため、時間が経つにつれて修正される可能性があるため、チェックしてください 回答のバージョン履歴 エラーを表示します)。

162
Greg Mattes

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" };
47
kaliatech
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";
    }
}
33
Anand Shekhar
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)];
}
14
ocodo

質問は少し古いです。この質問は非常にうるさいので、静的メソッドで解決したことをユーティリティとして投稿します。コピーして貼り付けて使用するだけです!

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

目的のテスト用

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

出力:

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
14
Sarz

現代の答えに貢献したいと思います。 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

古い回答

このコードは短いですが、私見はそれほどエレガントではありません。

    // 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の多くの機能の1つは、intとして月の日付を取得することが簡単で信頼できることです。これは、テーブルから適切なサフィックスを選択するために明らかに必要です。

ユニットテストも書くことをお勧めします。

PS同様のフォーマッタは、解析1st2ndなどの序数を含む日付文字列にも使用できます。それは この質問:Java-オプションの秒で日付を解析する で行われました。

リンク:Oracleチュートリアル:日時Java.timeの使用方法の説明。

8
Ole V.V.

国際化を意識しようとすると、ソリューションはさらに複雑になります。

問題は、他の言語では、接尾辞が数字自体だけでなく、それが数える名詞にも依存する可能性があることです。たとえば、ロシア語では「2-ойдень」ですが、「2-аянеделя」(これらは「2日目」を意味しますが、「2週目」を意味します)。これは日のみをフォーマットする場合には適用されませんが、もう少し一般的な場合には、複雑さに注意する必要があります。

ニースのソリューション(実際に実装する時間がなかった)は、親クラスに渡す前にLocale対応のMessageFormatを適用するようにSimpleDateFormetterを拡張することだと思います。このようにして、3月のフォーマット%Mで「3番目」、%MMで「03-rd」、%MMMで「3番目」を取得できるようにサポートできます。このクラスは外部からは通常のSimpleDateFormatterのように見えますが、より多くの形式をサポートしています。また、このパターンが通常のSimpleDateFormetterによって誤って適用された場合、結果は誤ってフォーマットされますが、それでも読み取り可能です。

8
C.A.B.

ここの例の多くは、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";
}
4
sivag1

マニュアル形式に基づいた英語のみのソリューションを求める回答に満足することはできません。しばらくの間、適切なソリューションを探していましたが、ようやく見つかりました。

RuleBasedNumberFormat を使用する必要があります。完璧に機能し、ロケールを尊重します。

これを行う簡単で確実な方法があります。使用する必要がある関数はgetDateFromDateString(dateString);です。基本的に、日付文字列の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;

}

2

Gregが提供するソリューションの唯一の問題は、「10」の数字で終わる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";
    }
}
2
Talisphere

パターンd'00'が見つかった場合に、正しいサフィックスリテラルでDateTimeFormatterパターンを更新する方法を次に示します。月1日の場合は、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による回答。より適切かもしれません

1
tazmaniax

このパターンを取得するためのヘルパーメソッドを自分で作成しました。

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
1
SamzSakerz

Androidでこれが必要な場合は、チェックアウトできます この回答

ただし、これは国際化されたソリューションです。そして、あなたは自転車を再発明する必要はありません;)

0
Alexander Krol

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")
0
Mohit Suthar