【问题标题】:What's the best way to parse an XML dateTime in Java?在 Java 中解析 XML dateTime 的最佳方法是什么?
【发布时间】:2010-10-28 21:13:40
【问题描述】:

在 Java 中解析 XML 日期时间的最佳方法是什么?合法的 dateTime 值包括 2002-10-10T12:00:00-05:00 和 2002-10-10T17:00:00Z

是否有一个很好的开源库可供我使用,或者我应该使用 SimpleDateFormat 或类似工具自行开发?

【问题讨论】:

    标签: java xml


    【解决方案1】:

    我想你想要来自Joda TimeISODateTimeFormat.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 调用要求它。)

    【讨论】:

    • 这很有帮助!为了保持原来的时区偏移,我使用了 DateTimeFormatter XML_DATE_TIME_FORMAT = ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed()
    【解决方案2】:

    理想情况下,模式感知(或用作事物基础)的 XML 处理包应该为类型化内容提供访问器。我知道一个(http://woodstox.codehaus.org/),但它(还)不提供对日期/时间的访问,只是提供更简单的类型(数字、数组、QNames 等)。有一个支持 javax.xml.datatype.XMLGregorianCalendar 的请求。

    唉,没有多少人这样做。但是,如果您使用的是特定的包(如 XOM 或 JDOM 等),在他们的用户列表上问这个问题可能不是一个坏主意。

    【讨论】:

      【解决方案3】:

      StaxMan 是绝对正确的。为了使用 SimpleDateFormat,您需要关闭每个 SimpleDateFormat 中的松散解析并迭代几种 SimpleDateFormat 格式,直到找到解析日期而不抛出异常的格式。如果您保持松散的解析,当您并不真正想要匹配时,您很容易得到匹配,并且lexical space of XSD:DateTime 在格式上留下了一些 SimpleDateFormat 无法在单个表达式中处理的灵活性。

      XML Schema 1.0 确实使用 ISO 8601,正如 Jon Skeet 所建议的,Joda Time 实施了 ISO 8601,因此这是一个有效的选项。

      如果您想将其全部保存在本机 Java 包中,您还可以使用 XMLGregorianCalendarDatatypeFactory 来解析和创建 XSD:Datetime 字符串。

      请参阅 DatatypeFactory.newXMLGregorianCalendar 和 XMLGregorianCalendar.toXMLFormat

      【讨论】:

        【解决方案4】:

        http://xmlbeans.apache.org/samples/DateTime.html

        有 XmlDateTime 类。只需执行 XMLDateTime.stringToDate(xmlDateTime)。

        【讨论】:

          【解决方案5】:

          【讨论】:

          • 我发现这是最简单的方法,无需添加另一个库。谢谢!
          • 这很好,但它允许没有时间戳的“dateTime”值,以及带有时间戳的“dateTimeStamp”值。有没有办法要求其中之一?
          • 升级到 java 11 后立即停止工作,因为 javax.xml.bind 包已在 11 中从 JDK/JRE 中删除。
          【解决方案6】:

          在 XML Beans v2 中它应该是 XmlDateTime.Factory.parse(dateTimeString),但这很尴尬,因为它需要一个带有像 <mytime>2011-10-20T15:07:14.112-07:00</mytime> 这样的开始和结束标签的元素

          更简单的方法是致电(new org.apache.xmlbeans.GDate(dateTimeString)).getDate()

          【讨论】:

            【解决方案7】:

            请参阅Parse and format dateTime values,尽管: - 它以“GMT”作为默认时区 - 如果有尾随不可解析部分,它不会抱怨 -不考虑TimeZone在错误的“GMT+xxxx”上默认为“GMT”

            【讨论】:

              【解决方案8】:

              您还可以在javax.xml.datatype.DatatypeFactory 中使用newXMLGregorianCalendar,它为您提供详细的控制,包括检测是否指定了时区。

              【讨论】:

              • 在哪里可以找到javax.xml.datatype.DatatypeFactory 的实现?我发现的唯一一个在 xerces2 中......我认为 xerces2 已经过时了......(我会在一段时间后回到 Java)
              • 你不需要找到一个——使用DatatypeFactory.newInstance(),你的JVM会搜索一个安装了Java的。
              • 对--一旦我弄清楚了,我应该删除我的问题。
              【解决方案9】:

              tl;博士

              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 没有定义文本以外的任何数据类型。

              使用 java.time

              输入字符串恰好符合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.time 框架内置于 Java 8 及更高版本中。这些类取代了旧的麻烦的日期时间类,例如 java.util.Date.Calendarjava.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 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 等等。

              【讨论】:

                猜你喜欢
                • 2010-10-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-11-30
                • 2015-08-21
                • 1970-01-01
                • 2019-09-16
                相关资源
                最近更新 更多