关于XML:Java——如何检查日历实例是否是错误的日期

java - How to check if a Calendar instance was originally a wrong date

我有一个日历实例,由JAXB通过javax.xml.bind.DatatypeConverter.parseDateTime方法从xsd datetime解析。

在运行时,我在一个Web服务中,我想知道原始XSD日期时间是否有效(月份<12,日期<31,30,29,28根据月份…等)。示例:这是一个有效日期:2015-07-30T09:32:05.543+02:00,而不是:2015-07-35T09:32:05.543+02:00

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

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

1
2
3
4
5
6
7
8
9
10
11
12
<?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>

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


DR

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

Java.时间

麻烦的旧日期时间类,如EDCOX1,1,EDCOX1,2,EDCX1,3,现在是被遗留的,被Java.Times类替换成Java 8和Java 9。

同样,joda时间项目现在处于维护模式,团队建议迁移到java.time类。

OffsetDateTimeDateTimeParseException

若要确定无效的日期时间字符串,请尝试分析并捕获异常。考虑到您的输入与UTC有一个偏移量,但不是时区,请将其解析为OffsetDateTime对象。无效输入引发DateTimeParseException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 ) ;
}

参见ideone.com上的代码运行。

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

java.time.format.DateTimeParseException: Text '2015-07-35T09:32:05.543+02:00' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 35

关于JavaTimes

JavaTimeFr框架是在Java 8和之后构建的。这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendar、&SimpleDateFormat

现在处于维护模式的joda time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。以及搜索堆栈溢出以获得许多示例和解释。规格为JSR 310。

在哪里获取java.time类?

  • Java SE 8、Java SE 9及以后
    • 内置的。
    • 标准JAVA API的一部分与捆绑实现。
    • Java 9添加了一些小的特性和修复。
  • Java SE 6和Java SE 7
    • 大部分JavaTimeActudio都被移植到TealEnter后端的Java 6和7中。
  • 安卓
    • java.time类的Android包实现的更高版本。
    • 对于早期的android,threetenabp项目适应threeten backport(如上所述)。看看如何使用三连珠……

threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。


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

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

这里我做了一个代码示例(它也回答了我的另一个问题:检查XSD DATETIME是否有一个定义的时区,然后转换为Java对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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(一个包装了JodTime的日期时间和错误代码的pojo)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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绑定文件。

1
2
3
4
5
6
7
8
<?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>