【问题标题】:java.util.Date to XMLGregorianCalendarjava.util.Date 到 XMLGregorianCalendar
【发布时间】:2010-10-24 13:37:22
【问题描述】:

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

【问题讨论】:

  • 仅供参考:这两个可怕的类在几年前都被 JSR 310 中定义的 java.time 类所取代。请参阅ZonedDateTime 类,新的转换方法添加到遗留类。 this Answer 中的详细信息,作者:Ole V.V.

标签: java xml date xmlgregoriancalendar


【解决方案1】:
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); }})
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    • Date 设计一直很差,已经有 20 多年的历史了。这很简单:不要使用它。
    • XMLGregorianCalendar 也很旧,设计也很老式。据我了解,它用于为 XML 文档生成 XML 格式的日期和时间。喜欢2009-05-07T19:05:45.678+02:002009-05-07T17:05:45.678Z。这些格式与 ISO 8601 非常吻合,因此现代 Java 日期和时间 API 的 java.time 类可以生成它们,这是我们更喜欢的。

    无需转换

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

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

    此 sn-p 的示例输出:

    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

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

        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 的答案。

    链接

    【讨论】:

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

    这是一种从 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);
       }
    
    }
    

    编辑:Slooow :-)

    【讨论】:

    • 这是一个将 GregorianCalendar 转换为 XMLGregorianCalendar 而不是问题中指示的解决方案
    【解决方案5】:

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

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

    感谢Nicolas Mommaertsthe accepted answer 的评论。

    【讨论】:

      【解决方案6】:

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

      注意有几个 gothca,例如必须在月份中添加一个(因为 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);
      

      【讨论】:

        【解决方案7】:

        我希望我的编码是正确的;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
        【解决方案8】:

        假设您正在解码或编码 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 可能也可以。

        【讨论】:

          【解决方案9】:

          查看此代码:-

          /* 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?
          猜你喜欢
          • 2011-04-10
          • 1970-01-01
          • 2017-11-22
          • 2017-03-25
          • 2017-01-08
          • 2012-09-24
          • 2018-01-23
          • 2015-01-30
          • 2019-02-04
          相关资源
          最近更新 更多