【发布时间】:2010-10-28 21:13:40
【问题描述】:
在 Java 中解析 XML 日期时间的最佳方法是什么?合法的 dateTime 值包括 2002-10-10T12:00:00-05:00 和 2002-10-10T17:00:00Z
是否有一个很好的开源库可供我使用,或者我应该使用 SimpleDateFormat 或类似工具自行开发?
【问题讨论】:
在 Java 中解析 XML 日期时间的最佳方法是什么?合法的 dateTime 值包括 2002-10-10T12:00:00-05:00 和 2002-10-10T17:00:00Z
是否有一个很好的开源库可供我使用,或者我应该使用 SimpleDateFormat 或类似工具自行开发?
【问题讨论】:
我想你想要来自Joda Time 的ISODateTimeFormat.dateTimeNoMillis()。一般来说
我会强烈敦促您远离 Java 中的内置日期/日历类。 Joda Time 的设计要好得多,有利于不可变性(特别是格式化程序是不可变的和线程安全的),并且是 Java 7 中新的日期/时间 API 的基础。
示例代码:
import org.joda.time.*;
import org.joda.time.format.*;
class Test
{
public static void main(String[] args)
{
parse("2002-10-10T12:00:00-05:00");
parse("2002-10-10T17:00:00Z");
}
private static final DateTimeFormatter XML_DATE_TIME_FORMAT =
ISODateTimeFormat.dateTimeNoMillis();
private static final DateTimeFormatter CHECKING_FORMAT =
ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
static void parse(String text)
{
System.out.println("Parsing: " + text);
DateTime dt = XML_DATE_TIME_FORMAT.parseDateTime(text);
System.out.println("Parsed to: " + CHECKING_FORMAT.print(dt));
}
}
输出:
Parsing: 2002-10-10T12:00:00-05:00
Parsed to: 2002-10-10T17:00:00.000Z
Parsing: 2002-10-10T17:00:00Z
Parsed to: 2002-10-10T17:00:00.000Z
(请注意,在输出中两者都以相同的 UTC 时间结束。格式化的输出使用 UTC,因为我们通过 withZone 调用要求它。)
【讨论】:
XML_DATE_TIME_FORMAT = ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed()
理想情况下,模式感知(或用作事物基础)的 XML 处理包应该为类型化内容提供访问器。我知道一个(http://woodstox.codehaus.org/),但它(还)不提供对日期/时间的访问,只是提供更简单的类型(数字、数组、QNames 等)。有一个支持 javax.xml.datatype.XMLGregorianCalendar 的请求。
唉,没有多少人这样做。但是,如果您使用的是特定的包(如 XOM 或 JDOM 等),在他们的用户列表上问这个问题可能不是一个坏主意。
【讨论】:
StaxMan 是绝对正确的。为了使用 SimpleDateFormat,您需要关闭每个 SimpleDateFormat 中的松散解析并迭代几种 SimpleDateFormat 格式,直到找到解析日期而不抛出异常的格式。如果您保持松散的解析,当您并不真正想要匹配时,您很容易得到匹配,并且lexical space of XSD:DateTime 在格式上留下了一些 SimpleDateFormat 无法在单个表达式中处理的灵活性。
XML Schema 1.0 确实使用 ISO 8601,正如 Jon Skeet 所建议的,Joda Time 实施了 ISO 8601,因此这是一个有效的选项。
如果您想将其全部保存在本机 Java 包中,您还可以使用 XMLGregorianCalendar 和 DatatypeFactory 来解析和创建 XSD:Datetime 字符串。
请参阅 DatatypeFactory.newXMLGregorianCalendar 和 XMLGregorianCalendar.toXMLFormat
【讨论】:
http://xmlbeans.apache.org/samples/DateTime.html
有 XmlDateTime 类。只需执行 XMLDateTime.stringToDate(xmlDateTime)。
【讨论】:
【讨论】:
在 XML Beans v2 中它应该是 XmlDateTime.Factory.parse(dateTimeString),但这很尴尬,因为它需要一个带有像 <mytime>2011-10-20T15:07:14.112-07:00</mytime> 这样的开始和结束标签的元素
更简单的方法是致电(new org.apache.xmlbeans.GDate(dateTimeString)).getDate()。
【讨论】:
请参阅Parse and format dateTime values,尽管: - 它以“GMT”作为默认时区 - 如果有尾随不可解析部分,它不会抱怨 -不考虑TimeZone在错误的“GMT+xxxx”上默认为“GMT”
【讨论】:
您还可以在javax.xml.datatype.DatatypeFactory 中使用newXMLGregorianCalendar,它为您提供详细的控制,包括检测是否指定了时区。
【讨论】:
javax.xml.datatype.DatatypeFactory 的实现?我发现的唯一一个在 xerces2 中......我认为 xerces2 已经过时了......(我会在一段时间后回到 Java)
Instant instant = Instant.parse( "2002-10-10T17:00:00Z" );
OffsetDateTime odt = OffsetDateTime.parse( "2002-10-10T12:00:00-05:00" );
其他答案是正确的,但现在已过时。他们使用现在被 java.time 框架取代的麻烦的旧类。
没有“XML dateTime”之类的东西。 XML 没有定义文本以外的任何数据类型。
输入字符串恰好符合ISO 8601 标准格式。因此无需指定格式化模式,因为 java.time 类在解析/生成字符串时默认使用 ISO 8601。
Instant第二个输入字符串以Z结尾,是Zulu的缩写,意思是UTC。
Instant 类代表UTC 中时间轴上的一个时刻,分辨率为nanoseconds。
String input = "2002-10-10T17:00:00Z":
Instant instant = Instant.parse( input );
OffsetDateTime第一个输入字符串包含一个与 UTC 的偏移量,因此我们将其解析为 OffsetDateTime。
String input = "2002-10-10T12:00:00-05:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input );
ZonedDateTime如果您有一个特定的时区,而不仅仅是与 UTC 的偏移,请应用该时区。
使用proper time zone name 格式为continent/region。切勿使用不属于真实时区、不标准化、甚至不唯一(!)的 3-4 个字母缩写。
ZoneId zoneId = ZoneId.of( "America/Cancun" );
ZonedDateTime zdt = odt.atZone( zoneId );
java.time 框架内置于 Java 8 及更高版本中。这些类取代了旧的麻烦的日期时间类,例如 java.util.Date、.Calendar 和 java.text.SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。
大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android。
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 等等。
【讨论】: