在 LocalDate 和 XMLGregorianCalendar 之间转换

Posted

技术标签:

【中文标题】在 LocalDate 和 XMLGregorianCalendar 之间转换【英文标题】:Convert between LocalDate and XMLGregorianCalendar 【发布时间】:2015-06-28 07:28:56 【问题描述】:

在 Java 8 的 LocalDateXMLGregorianCalendar 之间转换的最佳方式是什么?

【问题讨论】:

和这里***.com/questions/835889/…回答的差不多 @AnkurAnand 我不认为这个问题非常相似——我需要从LocalDate 转换,而不是Date,我要求在两个方向上进行转换。答案可能相似,因为转换需要 Date 作为中间步骤,但问题不是。 【参考方案1】:

以下是一种从 LocalDate 转换为 XMLGregorianCalendar 的简单方法,它既保留了未定义的字段(小时、时区等),又高效(即不转换到字符串/从字符串转换)。与其他一些解决方案不同,这会导致 XML 日期没有时区,例如<date>2018-11-06</date> 而不是 <date>2018-11-06+01:00</date>

LocalDate date = ...;
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar();
xmlCal.setYear(date.getYear());
xmlCal.setMonth(date.getMonthValue());
xmlCal.setDay(date.getDayOfMonth());

转换回来有点简单:

XMLGregorianCalendar xmlCal = ...
LocalDate date = LocalDate.of(xmlCal.getYear(), xmlCal.getMonth(), xmlCal.getDay());

【讨论】:

【参考方案2】:

LocalDate 仅存储年/月/日信息。其中没有时间和时区信息。 XMLGregorianCalendar 存储日期(年/月/日)+可选时间和可选时区信息。

所以从 LocalDate 转换为 XMLGregorianCalendar 很简单:

LocalDate in;
XMLGregorianCalendar out;
in = LocalDate.parse("1999-11-11");
out = DatatypeFactory.newInstance().newXMLGregorianCalendar(in.toString());

从 XMLGregorianCalendar 转换为 LocalDate 可能不是那么简单,因为 XMLGregorianCalendar 可能包含您根本无法在 LocalDate 中存储的时间和时区信息。

但是,我猜如果您从 XMLGregorianCalendar 转换为 LocalDate,那么 XMLGregorianCalendar 是由非时区 xsd:date 元素(在 xml 中表示为 YYYY-MM-DD)产生的。在这种情况下,您应该像这样转换它:

XMLGregorianCalendar in;
LocalDate out;
in = DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-11-11");
out = LocalDate.parse(in.toXMLFormat());

整个例子:

    
        LocalDate in;
        XMLGregorianCalendar out;
        in = LocalDate.parse("1999-11-11");
        out = DatatypeFactory.newInstance().newXMLGregorianCalendar(in.toString());
        System.out.println("in: " + in.toString());
        System.out.println("out: " + out.toXMLFormat());
    
    
        XMLGregorianCalendar in;
        LocalDate out;
        in = DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-11-11");
        out = LocalDate.parse(in.toXMLFormat());
        System.out.println("in: " + in.toXMLFormat());
        System.out.println("out: " + out.toString());
    

【讨论】:

【参考方案3】:

LocalDate 转换为XMLGregorianCalendar

LocalDate date = LocalDate.now();
GregorianCalendar gcal = GregorianCalendar.from(date.atStartOfDay(ZoneId.systemDefault()));
XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);

转换回来更简单:

xcal.toGregorianCalendar().toZonedDateTime().toLocalDate();

【讨论】:

从 LocalDate 转换为 XMLGregorianCalendar 时,请避免使用 GregorianCalendar!问题是 GregorianCalendar 的时区是必填字段,但 LocalDate 中没有时区信息! 某些带有时区的日期会由于夏令时转换而导致时区值的一小部分,例如LocalDate.parse("1902-07-10").atStartOfDay(ZoneId.of("Asia/Riyadh")) 将导致1902-07-10T00:00+03:06:52[Asia/Riyadh] 时区值03:06:52 xcal.toGregorianCalendar().toZonedDateTime().toLocalDate(); 应该避免@MuhammadHewedy 提到的。夏令时存在问题,您可能会以错误的日期结束。更好的解决方案是LocalDateTime.parse(xcal.toString()).atOffset(OffsetDateTime.now().getOffset())【参考方案4】:

要将LocalDate 转换为XMLGregorianCalendar,您可以使用

LocalDate localDate = ...;
GregorianCalendar calender = new GregorianCalendar();
Date utilDate = Date.from( localDate.atStartOfDay( ZoneId.systemDefault() ).toInstant() );
calender.setTime(utilDate);     
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(calender);

并将XMLGregorianCalendar 转换回LocalDate

XMLGregorianCalendar xmlCal = ...;
Date utilDate = xmlCal.toGregorianCalendar().getTime();
LocalDate localDate = LocalDateTime.ofInstant( utilDate.toInstant(), ZoneId.systemDefault() ).toLocalDate();

【讨论】:

以上是关于在 LocalDate 和 XMLGregorianCalendar 之间转换的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8 LocalDate 使用方式;LocalDate 封装Util,LocalDate工具类

在 mongoDB 中存储 java 8 LocalDate

localdate如何返回成字符串前端

在数据库中使用Java 8 LocalDate和LocalDateTime进行Hibernate

Java Joda-Time ,将 LocalDate 分配给 Month 和 Year

如何在java8中愉快地处理日期和时间java8新增了localdate和localtim