我正在尝试将HTML5 datetime
输入字段中返回的日期作为值进行解析。在Opera中试一试看一个例子。返回的日期如下所示:2011-05-03T11:58:01Z
。
我想将其解析为Java Date或Calendar Object。
理想情况下,解决方案应该包含以下内容:
答案 0 :(得分:13)
因此,原则上这将使用不同的SimpleDateFormat模式完成。
此处列出了individual declarations in RFC 3339的模式列表:
yyyy
MM
dd
HH
mm
ss
.SSS
(S
表示毫秒 - 但不清楚如果这些数字多于或少于3位会发生什么。)+02:00
似乎不受支持 - 相反,它支持使用+0200
和{{GMT+02:00
,z
和一些命名时区的格式1}}。)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'
(为了简单起见,使用正则表达式,或者手动解析,以提高效率)。
答案 1 :(得分:13)
Instant.parse( "2011-05-03T11:58:01Z" )
实际上,RFC 3339仅仅是实际标准ISO 8601的简介。
RFC的不同之处在于它故意违反ISO 8601以允许零小时的负偏移(-00:00
)并且给出“偏移未知”的语义含义。这个语义对我来说似乎是一个非常糟糕的主意。我建议坚持使用更合理的ISO 8601规则。在ISO 8601中,没有任何偏移意味着偏移是未知的 - 一个明显的含义,而RFC规则是深奥的。
现代 java.time 类在解析/生成字符串时默认使用ISO 8601格式。
您的输入字符串代表UTC的时刻。最后Z
是Zulu
的缩写,表示UTC。
Instant
(不是Date
)现代班级Instant
代表UTC时刻。此类替换java.util.Date
,并使用更精细的纳秒分辨率而不是毫秒。
Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;
ZonedDateTime
(不是Calendar
)要查看某个地区(时区)用户使用的挂钟时间,请使用ZoneId
获取ZonedDateTime
。这个班级ZonedDateTime
取代java.util.Calendar
班。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
我强烈建议尽可能避免使用旧版日期时间类。但是,如果您必须与尚未更新为 java.time 的旧代码进行互操作,则可以来回转换。调用添加到旧类的新方法。
Instant
取代java.util.Date
。
java.util.Date myJUDate = java.util.Date.from( instant ) ; // From modern to legacy.
Instant instant = myJUDate.toInstant() ; // From legacy to modern.
ZonedDateTime
取代GregorianCalendar
。
java.util.GregorianCalendar myGregCal = java.util.GregorianCalendar.from( zdt ) ; // From modern to legacy.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.
如果您的java.util.Calendar
实际上是GregorianCalendar
,则为施放。
java.util.GregorianCalendar myGregCal = ( java.util.GregorianCalendar ) myCal ; // Cast to the concrete class.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.
关于你的问题的具体问题......
java.time 类内置于Java 8,9,10及更高版本中。稍后的Android中还包含一个实现。对于早期的Java和早期的Android,请参阅本答案的下一部分。
各种 java.time 类处理我所知道的每种ISO 8601格式。他们甚至处理了一些神秘地从标准版本后期消失的格式。
对于其他格式,请参阅各种类的parse
和toString
方法,例如LocalDate
,OffsetDateTime
等。此外,搜索Stack Overflow,因为有许多示例和关于此主题的讨论。
要验证输入字符串,请陷阱DateTimeParseException
。
try {
Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;
} catch ( DateTimeParseException e ) {
… handle invalid input
}
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:6)
刚刚发现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");
}
答案 3 :(得分:3)
Here是一种简单的方法。它可能适合您的需求。
答案 4 :(得分:3)
也许不是最优雅的方式,但肯定是我最近做的一个:
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
cal.setTime(sdf.parse(dateInString.replace("Z", "").replace("T", "-")));
答案 5 :(得分:2)
使用您拥有的格式,例如2011-05-03T11:58:01Z,下面的代码会做。但是,我最近在Chrome和Opera中尝试了html5 datetime,它给了我2011-05-03T11:58Z - >没有下面代码无法处理的ss部分。
new Timestamp(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(date).toGregorianCalendar().getTimeInMillis());
答案 6 :(得分:0)
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(datetimeInFRC3339format)
答案 7 :(得分: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));