java 解析日期时间字符串中日期的序数指示符( st, nd, rd, th )
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28514346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parsing a date’s ordinal indicator ( st, nd, rd, th ) in a date-time string
提问by hao
I checked the SimpleDateFormat
javadoc, but I am not able to find a way to parse the ordinal indicatorin a date format like this:
我检查了SimpleDateFormat
javadoc,但我找不到一种方法来解析这样的日期格式的序数指示符:
Feb 13th 2015 9:00AM
I tried "MMM dd yyyy hh:mma"
, but the days have to be in number for it to be correct?
我试过了"MMM dd yyyy hh:mma"
,但是天数必须很多才能正确?
Is it possible to parse the "13th" date using a SimpleDateFormat
without having to truncate the string?
是否可以使用 a 解析“第 13 个”日期SimpleDateFormat
而不必截断字符串?
回答by Bohemian
Java's SimpleDateFormat doesn't support an ordinal suffix, but the ordinal suffix is just eye candy - it is redundant and can easily be removed to allow a straightforward parse:
Java 的 SimpleDateFormat 不支持序数后缀,但序数后缀只是令人赏心悦目——它是多余的,可以轻松删除以允许直接解析:
Date date = new SimpleDateFormat("MMM dd yyyy hh:mma")
.parse(str.replaceAll("(?<=\d)(st|nd|rd|th)", ""));
The replace regex is so simple because those sequences won't appear anywhere else in a valid date.
替换正则表达式非常简单,因为这些序列不会出现在有效日期的其他任何地方。
To handle any language that appends any length of ordinal indicator characters from any language as a suffix:
处理将任何语言的任何长度的序数指示字符作为后缀的任何语言:
Date date = new SimpleDateFormat("MMM dd yyyy hh:mma")
.parse(str.replaceAll("(?<=\d)(?=\D* \d+ )\p{L}+", ""));
Some languages, eg Mandarin, prepend their ordinal indicator, but that could be handled too using an alternation - left as an exercise for the reader :)
一些语言,例如普通话,在它们的序数指示符之前,但这也可以使用交替来处理 - 留给读者练习:)
回答by Ole V.V.
Java 8 answer (and Java 6 and 7) (because when this question was asked in 2015, the replacement for SimpleDateFormat
was already out):
Java 8 答案(以及 Java 6 和 7)(因为在 2015 年提出这个问题时,替代品SimpleDateFormat
已经出来了):
DateTimeFormatter parseFormatter = DateTimeFormatter
.ofPattern("MMM d['st']['nd']['rd']['th'] uuuu h:mma", Locale.ENGLISH);
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, parseFormatter);
With the sample date from the question this yiedls:
使用来自问题的样本日期,这会产生:
2015-02-13T09:00
In the format pattern []
denotes optional parts and ''
denotes literal parts. So the pattern says that the number may be followed by st
, nd
, rd
or th
.
在格式中,模式[]
表示可选部分并''
表示文字部分。所以模式说数字后面可以跟st
, nd
,rd
或th
。
To use this in Java 6 or 7 you need ThreeTen Backport. Or for Android ThreeTenABP.
要在 Java 6 或 7 中使用它,您需要ThreeTen Backport。或者对于 Android ThreeTenABP。
Since those suffixes are special for English, and other languages/locales have completely other usages for writing dates and times (also they don't use AM/PM), I believe that unless you have other requirements, you should try to implement this for English dates and times only. Also you should give an English speaking locale explicitly so it will work independently of the locale setting of your computer or JVM.
由于这些后缀对于英语来说是特殊的,而其他语言/地区在书写日期和时间方面有完全其他的用法(它们也不使用 AM/PM),我相信除非您有其他要求,否则您应该尝试为仅限英文日期和时间。此外,您应该明确给出一个讲英语的语言环境,这样它就可以独立于您的计算机或 JVM 的语言环境设置工作。
I have tried to combine the best parts of answers by Hugoand myselfto a duplicate question. Under that duplicate questionthere are still more java 8 answers. One limitation of the above code is it doesn't have very strict validation: you will get away with Feb 13rd
and even Feb 13stndrdth
.
我试图将雨果和我自己的最佳答案结合到一个重复的问题中。在那个重复的问题下,还有更多的 java 8 答案。上述代码的一个限制是它没有非常严格的验证:您将逃脱Feb 13rd
甚至Feb 13stndrdth
.
Edit: My own favourite among my answers on ordinal indicators is this one. It's about formatting, but the formatter I present there works fine for parsing too.
编辑:在我对序数指标的回答中,我最喜欢的是这个。这是关于格式化的,但我在那里展示的格式化程序也适用于解析。
回答by Patrycja K
In case someone finds it useful: DateTimeFormatter builder. This formatter allows you to format and to parse UK dates with ordinal suffixes (eg. "1st January 2017"):
如果有人觉得它有用:DateTimeFormatter builder。此格式化程序允许您使用序数后缀(例如“2017 年 1 月 1 日”)格式化和解析英国日期:
public class UkDateFormatterBuilder
{
/**
* The UK date formatter that formats a date without an offset, such as '14th September 2020' or '1st January 2017'.
* @return an immutable formatter which uses the {@link ResolverStyle#SMART SMART} resolver style. It has no override chronology or zone.
*/
public DateTimeFormatter build()
{
return new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseLenient()
.appendText(DAY_OF_MONTH, dayOfMonthMapping())
.appendLiteral(' ')
.appendText(MONTH_OF_YEAR, monthOfYearMapping())
.appendLiteral(' ')
.appendValue(YEAR, 4)
.toFormatter(Locale.UK);
}
private Map<Long, String> monthOfYearMapping()
{
Map<Long, String> monthOfYearMapping = new HashMap<>();
monthOfYearMapping.put(1L, "January");
monthOfYearMapping.put(2L, "February");
monthOfYearMapping.put(3L, "March");
monthOfYearMapping.put(4L, "April");
monthOfYearMapping.put(5L, "May");
monthOfYearMapping.put(6L, "June");
monthOfYearMapping.put(7L, "July");
monthOfYearMapping.put(8L, "August");
monthOfYearMapping.put(9L, "September");
monthOfYearMapping.put(10L, "October");
monthOfYearMapping.put(11L, "November");
monthOfYearMapping.put(12L, "December");
return monthOfYearMapping;
}
private Map<Long, String> dayOfMonthMapping()
{
Map<Long, String> suffixes = new HashMap<>();
for (int day=1; day<=31; day++)
{
suffixes.put((long)day, String.format("%s%s", (long) day, dayOfMonthSuffix(day)));
}
return suffixes;
}
private String dayOfMonthSuffix(final int day)
{
Preconditions.checkArgument(day >= 1 && day <= 31, "Illegal day of month: " + 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";
}
}
}
Plus a fragment of the test class:
加上测试类的片段:
public class UkDateFormatterBuilderTest
{
DateTimeFormatter formatter = new UkDateFormatterBuilder().build();
@Test
public void shouldFormat1stJanuaryDate()
{
final LocalDate date = LocalDate.of(2017, 1, 1);
final String formattedDate = date.format(formatter);
Assert.assertEquals("1st January 2017", formattedDate);
}
@Test
public void shouldParse1stJanuaryDate()
{
final String formattedDate = "1st January 2017";
final LocalDate parsedDate = LocalDate.parse(formattedDate, formatter);
Assert.assertEquals(LocalDate.of(2017, 1, 1), parsedDate);
}
}
PS. I used Greg Mattes' solution for ordinal suffixes from here: How do you format the day of the month to say "11th", "21st" or "23rd" in Java? (ordinal indicator)
附注。我从这里使用了 Greg Mattes 的序数后缀解决方案: 如何在 Java 中格式化月份中的“11th”、“21st”或“23rd”?(序数指标)
回答by Pierre-Olivier Dybman
You should be using RuleBasedNumberFormat. It works perfectly and it's respectful of the Locale.
您应该使用RuleBasedNumberFormat。它完美运行,并且尊重语言环境。