具有输入日期字符串可能为
"2020-01-25T21:59:27Z"
或
"Sat Jan 25 20:06:07 +0000 2020"
或Long
并且希望显示的像是
Jan 25, 2020
如何获取所需的格式化日期字符串?
我的解决方案是为三种可能的输入格式构建三个格式化程序,然后针对每个输入依次尝试格式化程序。对于这个想法的简单演示:
DateTimeFormatter[] inputFormatters = {
DateTimeFormatter.ISO_INSTANT,
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss xx yyyy", Locale.ROOT),
new DateTimeFormatterBuilder()
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter()
};
DateTimeFormatter displayFormatter
= DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(Locale.US);
for (String inputString : new String[] {
"2020-01-25T21:59:27Z",
"Sat Jan 25 20:06:07 +0000 2020",
"1566777888999"
}) {
// try the formatters in turn and see which one works
for (DateTimeFormatter formatter : inputFormatters) {
try {
ZonedDateTime dateTime = formatter.parse(inputString, Instant.FROM)
.atZone(ZoneId.systemDefault());
System.out.format("%-30s was parsed to %s%n",
inputString, dateTime.format(displayFormatter));
break;
} catch (DateTimeParseException ignore) {
// Ignore, try next format
}
}
}
在我的时区(欧洲/哥本哈根)中,此代码段的输出是:
2020-01-25T21:59:27Z was parsed to Jan 25, 2020 Sat Jan 25 20:06:07 +0000 2020 was parsed to Jan 25, 2020 1566777888999 was parsed to Aug 26, 2019
由于在所有时区都不是同一日期,所以输出将随时区而变化。
我建议使用java.time,现代的Java日期和时间API。我看到您标记了simpledateformat问题,但众所周知SimpleDateFormat
类麻烦且久已过时,因此,建议不要使用它。而且我正在利用这样一个事实,您的第一种格式是标准ISO 8601,并且java.time具有内置的格式化程序DateTimeFormatter.ISO_INSTANT
。
我的第三个输入格式化程序,即long值输入格式器,将最后三个字符视为秒的毫秒数,并将其前的所有字符视为自纪元以来的秒数。最终结果是它解析了自该纪元以来的毫秒数。构建此格式化程序需要DateTimeFormatterBuilder
。
我承认我讨厌写这篇文章。我真的希望您能够避免臭名昭著的SimpleDateFormat
类以及它像Date
这样早已过时的亲信。由于我了解您的应用程序是无库的,因此Joda-Time和ThreeTenABP似乎都不是问题。抱歉。在这种情况下,由于SimpleDateFormat
无法解析很长的时间,因此我的方法是尝试一下字符串以确定格式,然后基于该字符串选择我的解析方式。
DateFormat inputIso = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
// This format resembles the output from Date.toString
DateFormat inputDatelike
= new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZ yyyy", Locale.ROOT);
DateFormat displayFormat
= DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US);
displayFormat.setTimeZone(TimeZone.getDefault());
for (String inputString : new String[] {
"2020-01-25T21:59:27Z",
"Sat Jan 25 20:06:07 +0000 2020",
"1566777888999"
}) {
Date parsedDate;
if (Character.isDigit(inputString.charAt(0))) {
if (inputString.contains("-")) {
parsedDate = inputIso.parse(inputString);
} else {
// long number of millis
parsedDate = new Date(Long.parseLong(inputString));
}
} else {
parsedDate = inputDatelike.parse(inputString);
}
System.out.format("%-30s was parsed to %s%n",
inputString, displayFormat.format(parsedDate));
}
输出与以前完全相同:
2020-01-25T21:59:27Z was parsed to Jan 25, 2020 Sat Jan 25 20:06:07 +0000 2020 was parsed to Jan 25, 2020 1566777888999 was parsed to Aug 26, 2019
[请注意,此处的无效输入可能会导致NumberFormatException
或ParseException
,因此请同时捕获两者。如果无法避免,则只能诉诸此解决方案。
java.time在较新和较旧的Android设备上均可正常运行。它只需要至少Java 6。
Instant::from
而不是常量Instant.FROM
。org.threeten.bp
导入日期和时间类。java.time
。java.time
的向后移植到Java 6和7(JSR-310的ThreeTen)。