ChatGPT解决这个技术问题 Extra ChatGPT

java.util.Date 到 XMLGregorianCalendar

难道没有从 java.util.Date 到 XMLGregorianCalendar 的便捷方法吗?

仅供参考:这两个糟糕的类在几年前被 JSR 310 中定义的 java.time 类所取代。请参阅 ZonedDateTime 类,以及添加到旧类中的新转换方法。 this Answer 中的详细信息,作者:Ole VV

B
Ben Noland
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);

将 getInstance() 保留为某个转换器类中的静态变量是否可以节省?我试图在 JavaDoc 中查找它,但找不到任何东西。有点难知道并发使用是否会有问题?
如果您愿意使用 JodaTime,您可以在一行中执行此操作:DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar())
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar(YYYY, MM, DD));
请注意 Calendar 不是线程安全的,因此 GregorianCalender 也不是。另请参阅stackoverflow.com/questions/12131324/…
一行版本 - DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar() {{ setTime(yourDate); }})
j
jstricker

对于那些可能最终在这里寻找相反转换的人(从 XMLGregorianCalendarDate):

XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();

O
Ole V.V.

我想退后一步,以现代的眼光看待这个 10 年前的问题。提到的类 DateXMLGregorianCalendar 现在已经过时了。我挑战它们的使用并提供替代方案。

日期总是设计得很糟糕,已经有 20 多年的历史了。这很简单:不要使用它。

XMLGregorianCalendar 也很旧,而且设计也很过时。据我了解,它用于为 XML 文档生成 XML 格式的日期和时间。比如 2009-05-07T19:05:45.678+02:00 或 2009-05-07T17:05:45.678Z。这些格式与 ISO 8601 非常吻合,java.time 类(现代 Java 日期和时间 API)可以生成它们,这是我们更喜欢的。

无需转换

对于许多(大多数?)用途,Date 的现代替代品将是 InstantInstant 是一个时间点(就像 Date 一样)。

    Instant yourInstant = // ...
    System.out.println(yourInstant);

此代码段的示例输出:

2009-05-07T17:05:45.678Z

它与我上面的示例 XMLGregorianCalendar 字符串的后者相同。大多数人都知道,它来自于 Instant.toStringSystem.out.println 隐式调用。使用 java.time,在许多情况下,我们不需要过去在 DateCalendarXMLGregorianCalendar 和其他类之间进行的转换(但在某些情况下,我们确实需要转换,但我是在下一节中向您展示一对)。

控制偏移

DateInstant 都没有时区和 UTC 偏移量。 Ben Noland 先前接受且仍然获得最高投票的答案使用 JVM 当前的默认时区来选择 XMLGregorianCalendar 的偏移量。为了在现代对象中包含偏移量,我们使用 OffsetDateTime。例如:

    ZoneId zone = ZoneId.of("America/Asuncion");
    OffsetDateTime dateTime = yourInstant.atZone(zone).toOffsetDateTime();
    System.out.println(dateTime);

2009-05-07T13:05:45.678-04:00

这再次符合 XML 格式。如果要再次使用当前 JVM 时区设置,请将 zone 设置为 ZoneId.systemDefault()

如果我绝对需要 XMLGregorianCalendar 怎么办?

有更多方法可以将 Instant 转换为 XMLGregorianCalendar。我将介绍一对夫妇,每一个都有其优点和缺点。首先,就像 XMLGregorianCalendar 产生类似 2009-05-07T17:05:45.678Z 的字符串一样,它也可以从这样的字符串构建:

    String dateTimeString = yourInstant.toString();
    XMLGregorianCalendar date2
            = DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTimeString);
    System.out.println(date2);

2009-05-07T17:05:45.678Z

Pro:它很短,我认为它不会给人任何惊喜。缺点:对我来说,将瞬间格式化为字符串并将其解析回来是一种浪费。

    ZonedDateTime dateTime = yourInstant.atZone(zone);
    GregorianCalendar c = GregorianCalendar.from(dateTime);
    XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
    System.out.println(date2);

2009-05-07T13:05:45.678-04:00

Pro:这是官方的转换。控制偏移量自然而然。缺点:它经过更多步骤,因此更长。

如果我们有约会怎么办?

如果您从旧版 API 获得了一个老式的 Date 对象,而您现在无法更改,请将其转换为 Instant

    Instant i = yourDate.toInstant();
    System.out.println(i);

输出和之前一样:

2009-05-07T17:05:45.678Z

如果要控制偏移量,请以与上述相同的方式进一步转换为 OffsetDateTime

如果您有一个老式的 Date 并且绝对需要一个老式的 XMLGregorianCalendar,只需使用 Ben Noland 的答案。

链接

Oracle 教程:日期时间解释如何使用 java.time。

W3Schools 上的 XSD 日期和时间数据类型。

维基百科文章:ISO 8601


您的回答并不是对原始问题的真正回答。当您可以在遗留代码和现代代码之间进行选择时,它既有趣又有趣。但是,如果您带着这个问题来到这里,那并不是您有选择的余地。即使您要转换的样本也是完全错误的,因为它在 java 7 及更低版本中不起作用。
谢谢@Nagh,感谢您的批评。我承认我估计大多数用户都会有选择。对于那些(许多或少数)邪恶的老板强迫他们使用 Java 7 的人,我建议通过 backport ThreeTen Backport 使用 java.time。您当然也可以查看许多其他答案。我仍然认为使用 Java 8 或更高版本的功能的代码是正确的,或者我在工作中编写的大多数代码都是完全错误的。你是对的:我更相信写出有帮助的答案(至少对某些人来说),而不是直接回答所提出的问题。
我更相信写有用的答案(至少对某些人来说)而不是我同意的直接答案,但是有用的答案必须包括直接答案才能真正有帮助。我仍然需要处理 Java 5 代码,所以请感受一下我的痛苦。
我感觉到你的痛苦,@Nagh。如果您可以选择,您可以查看 Joda-Time 以了解任何重要的日期和时间工作,它也可以开箱即用地生成 ISO 8601。一年半前写这个答案时,我认为重复许多其他人已经给出的直接答案是没有意义的。如果它丢失了,我同意,那么我会包括它。
日期仍然被大量使用。
s
sasuke

这是从 GregorianCalendar 转换为 XMLGregorianCalendar 的方法;我将把从 java.util.Date 转换为 GregorianCalendar 的部分作为练习留给你:

import java.util.GregorianCalendar;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateTest {

   public static void main(final String[] args) throws Exception {
      GregorianCalendar gcal = new GregorianCalendar();
      XMLGregorianCalendar xgcal = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(gcal);
      System.out.println(xgcal);
   }

}

编辑:慢 :-)


这是将 GregorianCalendar 转换为 XMLGregorianCalendar 而不是问题中所指示的解决方案
C
Community

使用 Joda-Time 库的单行示例:

XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());

归功于 Nicolas Mommaertsthe accepted answer 中的评论。


C
Community

只是想我会在下面添加我的解决方案,因为上面的答案不符合我的确切需求。我的 Xml 架构需要单独的日期和时间元素,而不是单个日期时间字段。上面使用的标准 XMLGregorianCalendar 构造函数将生成一个 DateTime 字段

请注意有几个哥特卡,例如必须在月份中添加一个(因为 java 从 0 开始计算月份)。

GregorianCalendar cal = new GregorianCalendar();
cal.setTime(yourDate);
XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH), 0);
XMLGregorianCalendar xmlTime = DatatypeFactory.newInstance().newXMLGregorianCalendarTime(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), 0);

J
Jean-François Savard

我希望我在这里的编码是正确的;D 为了让它更快,只需使用 GregorianCalendar 的丑陋 getInstance() 调用而不是构造函数调用:

import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateTest {

   public static void main(final String[] args) throws Exception {
      // do not forget the type cast :/
      GregorianCalendar gcal = (GregorianCalendar) GregorianCalendar.getInstance();
      XMLGregorianCalendar xgcal = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(gcal);
      System.out.println(xgcal);
   }

}

-1 用于使用 .getInstance()。 GregorianCalendar.getInstance() 相当于 Calendar.getInstance()Calendar.getInstance() 不能让它更快,因为它使用相同的 new GregorianCalendar(),但在它还检查默认区域设置之前,它可以创建日本或佛教日历,所以对于一些幸运的用户来说它将是 ClassCastException
C
Community

假设您正在解码或编码 xml 并使用 JAXB,则可以完全替换 dateTime 绑定并为模式中的每个日期使用“XMLGregorianCalendar”以外的其他内容。

通过这种方式,您可以让 JAXB 做重复的工作,同时您可以花时间编写可提供价值的出色代码。

jodatime DateTime 的示例:(使用 java.util.Date 也可以执行此操作 - 但有一定的限制。我更喜欢 jodatime,它是从我的代码中复制的,所以我知道它可以工作......)

<jxb:globalBindings>
    <jxb:javaType name="org.joda.time.LocalDateTime" xmlType="xs:dateTime"
        parseMethod="test.util.JaxbConverter.parseDateTime"
        printMethod="se.seb.bis.test.util.JaxbConverter.printDateTime" />
    <jxb:javaType name="org.joda.time.LocalDate" xmlType="xs:date"
        parseMethod="test.util.JaxbConverter.parseDate"
        printMethod="test.util.JaxbConverter.printDate" />
    <jxb:javaType name="org.joda.time.LocalTime" xmlType="xs:time"
        parseMethod="test.util.JaxbConverter.parseTime"
        printMethod="test.util.JaxbConverter.printTime" />
    <jxb:serializable uid="2" />
</jxb:globalBindings>

和转换器:

public class JaxbConverter {
static final DateTimeFormatter dtf = ISODateTimeFormat.dateTimeNoMillis();
static final DateTimeFormatter df = ISODateTimeFormat.date();
static final DateTimeFormatter tf = ISODateTimeFormat.time();

public static LocalDateTime parseDateTime(String s) {
    try {
        if (StringUtils.trimToEmpty(s).isEmpty())
            return null;
        LocalDateTime r = dtf.parseLocalDateTime(s);
        return r;
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static String printDateTime(LocalDateTime d) {
    try {
        if (d == null)
            return null;
        return dtf.print(d);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static LocalDate parseDate(String s) {
    try {
        if (StringUtils.trimToEmpty(s).isEmpty())
            return null;
        return df.parseLocalDate(s);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static String printDate(LocalDate d) {
    try {
        if (d == null)
            return null;
        return df.print(d);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static String printTime(LocalTime d) {
    try {
        if (d == null)
            return null;
        return tf.print(d);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static LocalTime parseTime(String s) {
    try {
        if (StringUtils.trimToEmpty(s).isEmpty())
            return null;
        return df.parseLocalTime(s);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

见这里:how replace XmlGregorianCalendar by Date?

如果您很乐意根据时区+时间戳映射到某个瞬间,而原始时区并不真正相关,那么 java.util.Date 可能也可以。


p
pringi

查看此代码:-

/* Create Date Object */
Date date = new Date();
XMLGregorianCalendar xmlDate = null;
GregorianCalendar gc = new GregorianCalendar();

gc.setTime(date);

try{
    xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
}
catch(Exception e){
    e.printStackTrace();
}

System.out.println("XMLGregorianCalendar :- " + xmlDate);

您可以查看完整示例 here


我不认为这个答案提供了什么新的东西。也许你可以编辑以前的答案而不是发布另一个几乎相同的答案。
如何为 XMLGregorianCalendar 做一个 dateFormat?
O
Orhan ERDOGAN

我的解决方案

public static XMLGregorianCalendar DateToXMLGregorianCalendar(Date date) {

    GregorianCalendar gregoriancalendar = new GregorianCalendar();
    gregoriancalendar.setTime(date);
    XMLGregorianCalendar xmlGregorianCalendar = new XMLGregorianCalendarImpl(gregoriancalendar);
    return xmlGregorianCalendar;
}