将Java日期转换为XML日期格式(反之亦然)

21

有没有一种好的简单方法可以将Java Date转换为XML日期字符串格式,反之亦然?

谢谢,

Andez


2
“XML日期字符串格式”指的是什么?你能发一些例子吗? - javamonkey79
9个回答

23

原始答案

我猜您所说的“XML日期格式”是指类似于“2010-11-04T19:14Z”的格式。实际上,这是ISO 8601格式。

您可以使用SimpleDateFormat(如其他人所建议的那样)、FastDateFormat或使用Joda Time进行转换,我认为它是专门为此目的而创建的。

编辑:代码示例和更多内容

正如earnshae在评论中提到的,本答案可以通过示例进行改进。

首先,我们必须明确原始答案已经过时了。这是因为Java 8引入了操作日期和时间的类-应该关注java.time包。如果您很幸运地正在使用Java 8,则应使用其中之一。但是,这些东西出奇地难以正确处理。

不是LocalDate(Time)

考虑以下示例:

LocalDateTime dateTime = LocalDateTime.parse("2016-03-23T18:21");
System.out.println(dateTime); // 2016-03-23T18:21

起初,看起来我们在使用本地用户的日期和时间。然而,如果您敢问,您将得到不同的结果。
System.out.println(dateTime.getChronology()); // ISO

这实际上是ISO时间。我相信它应该读作“UTC”,但无论如何,它没有本地时区的概念。因此,我们应该把它视为通用时间。
请注意,我们正在解析的字符串末尾没有“Z”。如果您除了日期和时间之外添加任何内容,将会出现java.time.format.DateTimeParseException。因此,如果我们想要解析ISO8601字符串,似乎这个类没有用处。

有救了:ZonedDateTime

幸运的是,有一个类可以解析ISO8601字符串 - 它就是java.time.ZonedDateTime
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2016-03-23T18:21+01:00");
System.out.println(zonedDateTime); // 2016-03-23T18:21+01:00
ZonedDateTime zonedDateTimeZulu = ZonedDateTime.parse("2016-03-23T18:21Z");
System.out.println(zonedDateTimeZulu); // 2016-03-23T18:21Z

这里唯一的问题是,你实际上需要使用时区标识。试图解析原始日期时间(即“2016-03-23T18:21”)将导致已经提到的RuntimeException。根据情况,您必须在LocalDateTimeZonedDateTime之间进行选择。
当然,你可以很容易地在这两者之间进行转换,所以这不应该是一个问题:
System.out.println(zonedDateTimeZulu.toLocalDateTime()); // 2016-03-23T18:21
// Zone conversion
ZonedDateTime cetDateTime = zonedDateTimeZulu.toLocalDateTime()
   .atZone(ZoneId.of("CET"));
System.out.println(cetDateTime); // 2016-03-23T18:21+01:00[CET]

我建议现在使用这些类。但是,如果你的工作描述包括考古学(意味着你没有足够幸运地使用超过2年的Java 8……),你可能需要使用其他东西。
简单日期格式的乐趣
我不是很喜欢https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html,但有时你别无选择。问题是它不是线程安全的,如果它不喜欢某些东西,它会在你面前抛出一个已检查的异常(即ParseException)。因此,这段代码片段相当丑陋:
private Object lock = new Object();
// ...
try {
    synchronized (lock) {
        // Either "2016-03-23T18:21+01:00" or "2016-03-23T18:21Z"
        // will be correctly parsed (mind the different meaning though)
        Date date = dateFormat.parse("2016-03-23T18:21Z");
        System.out.println(date); // Wed Mar 23 19:21:00 CET 2016
    }
} catch (ParseException e) {
    LOG.error("Date time parsing exception", e);
}

FastDateFormat

FastDateFormat是同步的,因此您至少可以摆脱同步块。但它是一个外部依赖项。但由于它是Apache Commons Lang并且被广泛使用,我想这是可以接受的。实际上,它在使用上非常类似于SimpleDateFormat

FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mmX");
try {
    Date fastDate = fastDateFormat.parse("2016-03-23T18:21+01:00");
    System.out.println(fastDate);
} catch (ParseException e) {
    LOG.error("Date time parsing exception", e);
}

JodaTime

使用Joda-Time,您可以认为以下内容有效:

DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();        
LocalDateTime dateTime = LocalDateTime.parse("2016-03-23T20:48+01:00", parser);
System.out.println(dateTime); // 2016-03-23T20:48:00.000

很不幸,无论你在最后一个位置放什么(Z、+03:00等),结果都是一样的。显然,它没有起作用。
嗯,你真的应该直接解析它:
DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
DateTime dateTime = parser.parseDateTime("2016-03-23T21:12:23+04:00");
System.out.println(dateTime); // 2016-03-23T18:12:23.000+01:00

现在没问题了。请注意,与其他答案不同,我使用了dateTimeParser()不是dateTime()。我注意到它们之间有微妙但重要的行为差异(Joda-Time 2.9.2)。但是,我将其留给读者来测试和确认。

+1 对于Joda Time的引用,它比SimpleDateFormat更好,后者充满了危险。 - Gary
是的,这就是我正在寻找的。干杯 Andez。 @Gary Rowe- 为什么它会引起争议?我已经使用它超过一年了,绝对讨厌 Java 日期和时间的所有东西。我们的公司有一个围绕 GregorianCalendar 的包装器,每次实例化时都会调用 TimeZone.setDefault("...")。我没有编写它,只是不得不与它一起工作或绕过它 :-( - Andez
这个答案如果附上代码会更好。 - earnshae

21

建议使用SimpleDateFormat。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
String date = sdf.format(new Date());
System.out.println(date);
Date d = sdf.parse(date);

我猜您需要的日期格式是yyyy-MM-dd'T'HH:mm:ss,同时可以参考http://www.w3schools.com/schema/schema_dtypes_date.asp


9

使用Joda Time,您需要执行以下操作:

DateTimeFormatter fmt = ISODateTimeFormat.dateTime(); // ISO8601 (XML) Date/time
DateTime dt = fmt.parseDateTime("2000-01-01T12:00:00+100"); // +1hr time zone
System.out.println(fmt.print(dt)); // Prints in ISO8601 format

线程安全、不可变且简单。


8
完美的方法,使用XMLGregorianCalendar:
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(v);
DatatypeFactory df = DatatypeFactory.newInstance();
XMLGregorianCalendar dateTime = df.newXMLGregorianCalendar(calendar);
return dateTime.toString();

7

只需在Java中使用SimpleDateFormat即可实现此目的...

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date = sdf.parse("2011-12-31T15:05:50+1000");

4
我建议使用Java内置的类javax.xml.bind.DatatypeConverter。它可以处理大多数xml简单类型的转换。对于日期,您需要通过Calendar对象进行一些繁琐的操作,但另一方面,它可以处理在xml datetime字段中出现的所有区域信息变体。
从xml:
    Calendar c = DatatypeConverter.parseDateTime("2015-10-21T13:25");
    Date d = c.getTime();

转换为XML:

    Date yourDate = new Date()
    Calendar c = Calendar.getInstance();
    c.setTime(yourDate);
    String xmlDateTime = DatatypeConverter.printDateTime(c);

编辑

自Java 9及以上版本起,DatatypeConverter类不再公开可见,因为它属于javax.xml.bind包。有关更多信息和可能的解决方案,请参见此问题。在这种情况下,loic vaugeois提出的使用XmlGregorianCalendar的解决方案要好得多。


3

您可以使用SimpleDateFormat解析和格式化日期,无论日期格式如何。


2

为了符合ISO8601标准,时区必须采用+HH:MM或- HH:MM的格式。

使用Simpledateformat时,必须使用XXX代替Z(请参见NovelGuy的回答)。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

1

如果不确定你需要的确切格式,通用的回答是:你可能需要使用DateFormat或SimpleDateFormat。这里有一个关于两者的不错教程here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接