我知道这会给我这个月的一天,一个数(11
,21
,23
):
SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");
但你如何格式化月份的一天,包括序数指标,比方说11th
,21st
还是23rd
?
SimpleDateFormat
上课。它不仅已经过时,而且非常麻烦。今天,我们java.time
在现代Java日期和时间API及其功能方面有了很多改进DateTimeFormatter
。
我知道这会给我这个月的一天,一个数(11
,21
,23
):
SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");
但你如何格式化月份的一天,包括序数指标,比方说11th
,21st
还是23rd
?
SimpleDateFormat
上课。它不仅已经过时,而且非常麻烦。今天,我们java.time
在现代Java日期和时间API及其功能方面有了很多改进DateTimeFormatter
。
Answers:
// 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";
}
}
java.lang.IllegalArgumentException
因为“一个非法的图案字符t”而出了名。
问题有点老了。由于此问题非常嘈杂,因此请发布我使用静态方法解决的问题。只需复制,粘贴和使用它!
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
我想贡献现代的答案。SimpleDateFormat
八年前问这个问题时,该班就可以使用,但是现在您应该避免使用它,因为它不仅已经过时,而且非常麻烦。使用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
是将月份中的天作为int
,这是直接且可靠的,这显然是从表中选择正确的后缀所必需的。
我建议您也编写一个单元测试。
PS类似的格式,也可用于分析含像序号日期字符串1st
,2nd
等等。这是在做了这样一个问题:爪哇-解析日期可选秒。
链接: Oracle教程:Date Time说明如何使用java.time
。
如果您尝试了解i18n,则解决方案将变得更加复杂。
问题在于,在其他语言中,后缀不仅取决于数字本身,还取决于其计数的名词。例如,俄语为“2-ойдень”,但是为“2-аянеделя”(它们的意思是“第二天”,但是“第二周”)。如果仅格式化几天,则不适用,但在更通用的情况下,您应该意识到复杂性。
我认为不错的解决方案(我没有时间实际实现)将是扩展SimpleDateFormetter以在传递给父类之前应用支持区域设置的MessageFormat。这样,您就可以支持让比如说三月格式的%M获得“ 3rd”,%MM获得“ 03-rd”和%MMM获得“第三”。从外部看,此类类似于常规的SimpleDateFormatter,但支持更多格式。同样,如果常规的SimpleDateFormetter错误地应用了此模式,则结果的格式将不正确,但仍可读。
我对基于手动格式的仅英语解决方案的回答感到不满意。我一直在寻找合适的解决方案已有一段时间了,终于找到了。
您应该使用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;
}
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";
}
}
th
11、12和13。我相信if ( hunRem - tenRem == 10 )
情况可以肯定。
RuleBasedNumberFormat
在ICU库中我感谢@ Pierre-Olivier Dybman(http://www.icu-project.org/apiref/icu4j/com/ibm/icu/text/RuleBasedNumberFormat.html)到ICU项目库的链接,但仍然需要弄清楚了解如何使用它,因此RuleBasedNumberFormat
下面是用法示例。
它只会格式化单个数字而不是整个日期,因此,如果要查找格式如下的日期,则需要构建一个组合字符串:例如2月3日,星期一。
以下代码RuleBasedNumberFormat
针对给定的区域设置将其设置为序号格式,创建一个java.time ZonedDateTime
,然后将其序号数字格式化为字符串。
RuleBasedNumberFormat numOrdinalFormat = new RuleBasedNumberFormat(Locale.UK,
RuleBasedNumberFormat.ORDINAL);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Pacific/Auckland"));
String dayNumAndOrdinal = numOrdinalFormat.format(zdt.toLocalDate().getDayOfMonth());
输出示例:
第三名
要么
第四名
等等
这是一种方法,如果找到正确的后缀文字,则使用正确的后缀文字更新DateTimeFormatter模式d'00'
,例如,对于第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回答。也许更合适
我为自己写了一个辅助方法来获取模式。
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
尝试以下功能:
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);
}
Date
,Calendar
和SimpleDateFormat
。这些类的设计很差,而且已经过时了,最后一个特别麻烦。取而代之的是使用java.time中的LocalDate
和DateTimeFormatter
,它们都是现代Java日期和时间API。另外,我不确定与其他18个答案相比,您的答案有哪些新贡献?
在科特林,您可以像这样使用
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")
可以使用以下方法获取传递给它的日期的格式化字符串。它将使用Java中的SimpleDateFormat将日期格式化为1st,2nd,3rd,4th..。例如:-2015年9月1日
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";
}
}