【问题标题】:java - How to check if a Calendar instance was originally a wrong datejava - 如何检查日历实例最初是否是错误的日期
【发布时间】:2015-07-30 07:30:25
【问题描述】:

我有一个 Calendar 实例,通过 JAXB 的 javax.xml.bind.DatatypeConverter.parseDateTime 方法从 XSD 日期时间解析。

在运行时,我在 Web 服务中,我想知道原始 xsd 日期时间是否有效(月 2015-07-30T09:32:05.543+02:00 而不是:2015-07-35T09:32:05.543+02:00

我尝试在 web 服务中的实例上使用setLenient,但是当原始日期错误时,它似乎不会引发异常。

有什么办法吗?我的猜测是在 global.jaxb 文件中告诉 JAXB 以正确的方式执行此操作,这是我现在使用的:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema"
               jaxb:extensionBindingPrefixes="xjc">
    <jaxb:globalBindings>
        <xjc:simple/>
        <xjc:serializable uid="-1"/>
        <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
                       parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
                       printMethod="javax.xml.bind.DatatypeConverter.printDateTime"/>
    </jaxb:globalBindings>
</jaxb:bindings>

任何帮助将不胜感激。谢谢。

【问题讨论】:

    标签: java xml web-services parsing jaxb


    【解决方案1】:

    tl;博士

    OffsetDateTime.parse( "2015-07-35T09:32:05.543+02:00" ) 
        … catch ( DateTimeParseException e )
    

    java.time

    麻烦的旧日期时间类,如 java.util.Date、java.util.Calendar 和 java.text.SimpleDateFormat 现在是 legacy,被 Java 8 和 Java 9 中内置的 java.time 类所取代。

    同样,Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。

    OffsetDateTime & DateTimeParseException

    要确定无效的日期时间字符串,请尝试解析并捕获异常。鉴于您的输入具有与 UTC 的偏移量但没有时区,请解析为 OffsetDateTime 对象。无效的输入抛出DateTimeParseException。

    String inputGood = "2015-07-30T09:32:05.543+02:00" ;
    String inputBad = "2015-07-35T09:32:05.543+02:00" ;
    
    try{ 
        // Good
        OffsetDateTime odtGood = OffsetDateTime.parse( inputGood ) ;
        System.out.println( "odtGood.toString(): " + odtGood ) ;
    
        // Bad
        OffsetDateTime odtBad = OffsetDateTime.parse( inputBad ) ;
        System.out.println( "odtBad.toString(): " + odtBad ) ;
    } catch ( DateTimeParseException e ) {
        System.out.println( e ) ;
    }
    

    见code run live at IdeOne.com。

    odtGood.toString(): 2015-07-30T09:32:05.543+02:00

    java.time.format.DateTimeParseException:无法解析文本“2015-07-35T09:32:05.543+02:00”:DayOfMonth 的值无效(有效值 1 - 28/31):35


    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。

    【讨论】:

      【解决方案2】:

      我通过在 custom JAXB bindings 文件中使用 JodaTime 的 ISODateTimeFormat#dateTimeParser() 和自定义适配器解决了我的问题。 JodaTime 是比 Calendar 标准 Java API 更好的 API,默认情况下它是不宽松的。

      我可以为日历做同样的事情,但我应该自己定义所有格式,JodaTime 已经定义了它们。

      这是我制作的代码示例(它也回答了我的另一个问题:Check if xsd datetime had a defined timezone before conversion to Java object)

      package com.app.adapter;
      public class MyDatetimeAdapter extends XmlAdapter<String, DateTime> {
          private final static DateTimeFormatter DATETIME_FORMATTER = ISODateTimeFormat.dateTime();
          private final static Pattern TIMEZONE_PATTERN = Pattern.compile("(\\+|\\-)[0-9]{2}:[0-9]{2}$");
          @Override
          public DateTime unmarshal(String string) throws Exception {
              string = string.trim();
                  try { 
                  DateTime tmp = ISODateTimeFormat.dateTimeParser().parseDateTime(string);
      
                  if (string.charAt(string.length()-1) == 'Z' || TIMEZONE_PATTERN.matcher(string).find()) {
                      return new CustomDateTime(tmp);
                  }
                  return new CustomDateTime(tmp, CustomDateTime.Error.NO_TIMEZONE);
              } catch (IllegalArgumentException e) {
                  return new CustomDateTime(null, CustomDateTime.Error.INVALID);
              }
          }
      
          @Override
          public String marshal(CustomDateTime date) throws Exception {
              return DATETIME_FORMATTER.print(date.getDateTime());
          }
      }
      

      这里是 CustomDateTime(一个包含 JodaTime 的 DateTime 和错误代码的 POJO)

      package com.app.types;
      public final class CustomDateTime {
      
          private DateTime dateTime;
          private Error error;
      
          // getter .. setters .. constructor
      
          public static CustomDateTime getInstance(Error error) {
              return new CustomDateTime(DateTime.now(), error);
          }
      
          public static CustomDateTime getInstance() {
              return getInstance(Error.NONE);
          }
      
          public enum Error {
              NONE,
              NO_TIMEZONE
              INVALID;
          }
      }
      

      最后是 JAXB 绑定文件。

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"
                     xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.1">
          <jaxb:globalBindings>
              <xjc:javaType adapter="com.app.adapter.MyDatetimeAdapter"
                            name="com.app.types.CustomDateTime" xmlType="xs:dateTime"/>
          </jaxb:globalBindings>
      </jaxb:bindings>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-24
        • 1970-01-01
        相关资源
        最近更新 更多