我需要用Java解析格式“2010年1月10日”的日期。我怎么能这样做?
如何处理追踪日期编号的ordinal indicators,st
,nd
,rd
或th
?
答案 0 :(得分:9)
这有效:
String s = "January 10th, 2010";
DateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy");
System.out.println("" + dateFormat.parse(s.replaceAll("(?:st|nd|rd|th),", "")));
但您需要确保使用正确的Locale
来正确解析月份名称。
我知道你可以在SimpleDateFormat
模式中包含一般文本。但是在这种情况下,文本依赖于信息,实际上与解析过程无关。
这实际上是我能想到的最简单的解决方案。但我希望被证明是错的。
您可以通过执行与此类似的操作来避免其中一条评论中出现的陷阱:
String s = "January 10th, 2010";
DateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy");
System.out.println("" + dateFormat.parse(s.replaceAll("(?<= \\d+)(?:st|nd|rd|th),(?= \\d+$)", "")));
这样您就无法匹配Jath,uary 10 2010
。
答案 1 :(得分:1)
您可以将nd
等设置为SimpleDateFormat中的文字。您可以定义所需的四种格式并尝试它们。首先从th
开始,因为我猜这种情况会更频繁发生。如果它与ParseException
失败,请尝试下一个。如果全部失败,则抛出ParseException。这里的代码只是一个概念。在现实生活中,您可能不会每次都生成新的格式,并且可能会考虑线程安全性。
public static Date hoolaHoop(final String dateText) throws ParseException
{
ParseException pe=null;
String[] sss={"th","nd","rd","st"};
for (String special:sss)
{
SimpleDateFormat sdf=new SimpleDateFormat("MMMM d'"+special+",' yyyy");
try{
return sdf.parse(dateText);
}
catch (ParseException e)
{
// remember for throwing later
pe=e;
}
}
throw pe;
}
public static void main (String[] args) throws java.lang.Exception
{
String[] dateText={"January 10th, 2010","January 1st, 2010","January 2nd, 2010",""};
for (String dt:dateText) {System.out.println(hoolaHoop(dt))};
}
输出:
Sun 1月10日00:00:00 GMT 2010
Fri Jan 01 00:00:00 GMT 2010
2010年1月2日星期六00:00:00 GMT
线程“main”中的异常java.text.ParseException:Unparseable date:“”
"th","nd","rd","st"
当然只适用于具有英语的语言环境。记在脑子里。在法国,我猜"re","nd"
等。
答案 2 :(得分:1)
我想贡献现代的答案。而不是今天在两个投票最多的答案中使用的SimpleDateFormat
类,您应该使用java.time(现代Java日期和时间API)。它提供了两个不错的解决方案。
我们首先定义一个用于解析的格式化程序:
private static final DateTimeFormatter PARSING_FORMATTER = DateTimeFormatter.ofPattern(
"MMMM d['st']['nd']['rd']['th'], uuuu", Locale.ENGLISH);
然后我们像这样使用它:
String dateString = "January 10th, 2010";
LocalDate date = LocalDate.parse(dateString, PARSING_FORMATTER);
System.out.println("Parsed date: " + date);
输出为:
分析日期:2010-01-10
格式模式字符串中的方括号[]
包含可选部分,单引号包含文字文本。因此,d['st']['nd']['rd']['th']
意味着一个月的一天之后可能会有st
,nd
,rd
和/或th
。
上述方法有两个局限性
10st
甚至10stndrdth
。January 10stndrdth, 2010
)。如果您想更好地验证序号指示器,或者希望将日期格式化回字符串,则可以通过以下方式构建格式化程序:
private static final DateTimeFormatter FORMATTING_AND_PARSING_FORMATTER;
static {
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");
}
FORMATTING_AND_PARSING_FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("MMMM ")
.appendText(ChronoField.DAY_OF_MONTH, ordinalNumbers)
.appendPattern(", uuuu")
.toFormatter(Locale.ENGLISH);
}
这将解析与上面相同的日期字符串。我们还要尝试进行格式化:
System.out.println("Formatted back using the same formatter: "
+ date.format(FORMATTING_AND_PARSING_FORMATTER));
使用相同的格式化程序重新格式化:2010年1月10日
答案 3 :(得分:0)
这是另一种简单的方法,但需要包含 apache commons jar 。
import org.apache.commons.lang.time.*;
String s = "January 10th, 2010";
String[] freakyFormat = {"MMM dd'st,' yyyy","MMM dd'nd,' yyyy","MMM dd'th,' yyyy","MMM dd'rd,' yyyy"};
DateUtils du = new DateUtils();
System.out.println("" + du.parseDate(s,freakyFormat));