34

我正在尝试解析作为 HTML5datetime输入字段中的值返回的日期。在 Opera 中试试看一个例子。返回的日期如下所示:2011-05-03T11:58:01Z

我想将其解析为 Java 日期或日历对象。

理想情况下,解决方案应具有以下内容:

  • 没有外部库(罐子)
  • 处理所有可接受的 RFC 3339 格式
  • 应该能够轻松验证字符串以查看它是否是有效的 RFC 3339 日期
4

9 回答 9

30
于 2018-04-03T21:40:52.967 回答
15

因此,原则上这将使用不同的SimpleDateFormat模式来完成。

这里是RFC 3339 中各个声明的模式列表:

  • 日期: yyyy
  • 日期-月份: MM
  • 日期-mday: dd
  • 时间小时: HH
  • 时间-分钟: mm
  • 时间秒: ss
  • time-secfrac:( .SSS 表示S毫秒,但不清楚如果这些数字多于或少于 3 位会发生什么。)
  • time-numoffset:(+02:00好像不支持 - 相反它支持格式+0200,以及一些使用和的GMT+02:00命名时区。)zZ
  • 时间偏移:( 'Z' 不支持其他时区)-您应该在使用format.setTimezone(TimeZone.getTimeZone("UTC"))之前使用。)
  • 部分时间: HH:mm:ssHH: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从头开始实现一个更好的主意(为了简单起见,使用正则表达式,或者为了效率而手动解析)。

于 2011-05-18T01:23:51.060 回答
13

刚刚发现google在Google HTTP Client Library中实现了Rfc3339解析器

https://github.com/google/google-http-java-client/blob/dev/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

经测试。它可以很好地解析不同的亚秒时间片段。

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");
}
于 2018-04-03T16:03:27.743 回答
2

使用您拥有的格式,例如 2011-05-03T11:58:01Z,下面的代码就可以了。但是,我最近在 Chrome 和 Opera 中试用了 html5 日期时间,它给了我 2011-05-03T11:58Z --> 没有下面的代码无法处理的 ss 部分。

new Timestamp(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(date).toGregorianCalendar().getTimeInMillis());
于 2011-08-16T08:16:06.910 回答
2

也许不是最优雅的方式,但肯定是我最近制作的一种方式:

Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
cal.setTime(sdf.parse(dateInString.replace("Z", "").replace("T", "-")));
于 2017-01-10T12:54:15.267 回答
1

为了将来参考,作为替代方案,您可以使用手写的 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()
}

[1] - https://github.com/ethlo/itu

于 2022-02-28T10:49:26.420 回答
0

我正在使用这个:

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));
于 2020-07-26T14:33:43.193 回答
0

虽然,这个问题已经很老了,但它可能会对想要这个答案的 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
于 2022-01-18T10:03:29.523 回答
-1
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(datetimeInFRC3339format)
于 2018-02-14T11:55:54.090 回答