我正在尝试解析作为 HTML5datetime
输入字段中的值返回的日期。在 Opera 中试试看一个例子。返回的日期如下所示:2011-05-03T11:58:01Z
。
我想将其解析为 Java 日期或日历对象。
理想情况下,解决方案应具有以下内容:
- 没有外部库(罐子)
- 处理所有可接受的 RFC 3339 格式
- 应该能够轻松验证字符串以查看它是否是有效的 RFC 3339 日期
我正在尝试解析作为 HTML5datetime
输入字段中的值返回的日期。在 Opera 中试试看一个例子。返回的日期如下所示:2011-05-03T11:58:01Z
。
我想将其解析为 Java 日期或日历对象。
理想情况下,解决方案应具有以下内容:
因此,原则上这将使用不同的SimpleDateFormat模式来完成。
这里是RFC 3339 中各个声明的模式列表:
yyyy
MM
dd
HH
mm
ss
.SSS
表示S
毫秒,但不清楚如果这些数字多于或少于 3 位会发生什么。)+02:00
好像不支持 - 相反它支持格式+0200
,以及一些使用和的GMT+02:00
命名时区。)z
Z
'Z'
不支持其他时区)-您应该在使用format.setTimezone(TimeZone.getTimeZone("UTC"))
之前使用。)HH:mm:ss
或HH:mm:ss.SSS
。HH:mm:ss'Z'
或HH:mm:ss.SSS'Z'
。yyyy-MM-dd
yyyy-MM-dd'T'HH:mm:ss'Z'
或yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
正如我们所看到的,这似乎无法解析所有内容。也许RFC3339DateFormat
从头开始实现一个更好的主意(为了简单起见,使用正则表达式,或者为了效率而手动解析)。
刚刚发现google在Google HTTP Client Library中实现了Rfc3339解析器
经测试。它可以很好地解析不同的亚秒时间片段。
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import com.google.api.client.util.DateTime;
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.withZone(ZoneId.of("UTC"));
@Test
public void test1e9Parse() {
String timeStr = "2018-04-03T11:32:26.553955473Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.553Z");
}
@Test
public void test1e3Parse() {
String timeStr = "2018-04-03T11:32:26.553Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.553Z");
}
@Test
public void testEpochSecondsParse() {
String timeStr = "2018-04-03T11:32:26Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.000Z");
}
使用您拥有的格式,例如 2011-05-03T11:58:01Z,下面的代码就可以了。但是,我最近在 Chrome 和 Opera 中试用了 html5 日期时间,它给了我 2011-05-03T11:58Z --> 没有下面的代码无法处理的 ss 部分。
new Timestamp(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(date).toGregorianCalendar().getTimeInMillis());
也许不是最优雅的方式,但肯定是我最近制作的一种方式:
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
cal.setTime(sdf.parse(dateInString.replace("Z", "").replace("T", "-")));
为了将来参考,作为替代方案,您可以使用手写的 ITU[1] 来准确处理 RFC-3339 解析,并且还可以让您轻松处理闰秒。该库是无依赖关系的,仅重 18 kB。
全面披露:我是作者
try
{
final OffsetDateTime dateTime = ITU.parseDateTime(dateTimeStr);
}
catch (LeapSecondException exc)
{
// The following helper methods are available let you decide how to progress
//int exc.getSecondsInMinute()
//OffsetDateTime exc.getNearestDateTime()
//boolean exc.isVerifiedValidLeapYearMonth()
}
我正在使用这个:
DateTimeFormatter RFC_3339_DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE_TIME)
.optionalStart()
.appendOffset("+HH:MM", "Z")
.optionalEnd()
.toFormatter();
例子:
String dateTimeString = "2007-05-01T15:43:26.3452+07:00";
ZonedDateTime zonedDateTime = ZonedDateTime.from(RFC_3339_DATE_TIME_FORMATTER.parse(dateTimeString));
虽然,这个问题已经很老了,但它可能会对想要这个答案的 Kotlin 版本的人有所帮助。通过使用此文件,任何人都可以将 Rfc3339 日期转换为任何日期格式。在这里,我取一个空文件名DateUtil
并创建一个名为的函数,该函数getDateString()
具有 3 个参数。
1st argument : Your input date
2nd argument : Your input date pattern
3rd argument : Your wanted date pattern
DateUtil.kt
object DatePattern {
const val DAY_MONTH_YEAR = "dd-MM-yyyy"
const val RFC3339 = "yyyy-MM-dd'T'HH:mm:ss'Z'"
}
fun getDateString(date: String, inputDatePattern: String, outputDatePattern: String): String {
return try {
val inputFormat = SimpleDateFormat(inputDatePattern, getDefault())
val outputFormat = SimpleDateFormat(outputDatePattern, getDefault())
outputFormat.format(inputFormat.parse(date))
} catch (e: Exception) {
""
}
}
现在在您的活动/功能/数据源映射器中使用此方法以字符串格式获取日期,如下所示
getDate("2022-01-18T14:41:52Z", RFC3339, DAY_MONTH_YEAR)
输出将是这样的
18-01-2022
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(datetimeInFRC3339format)