Java - serializing/deserializing 日期时出错

Java - Error when serializing/deserializing the date

我无法弄清楚这种日期格式是什么:2019-02-28T12:17:46.279+0000。我尝试了不同的日期格式来获得此结果,但没有任何效果。最接近的模式是:yyyy-MM-dd'T'HH:mm:ss.SSSZ 但是这种模式的输出是这样的:2019-02-28T12:17:46.279-0000- 是在秒之后而不是 +

我得到这个异常:

Caused by: java.lang.IllegalArgumentException: 2019-02-28T12:17:46.279+0000
    at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl$Parser.skip(XMLGregorianCalendarImpl.java:2932)
    at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl$Parser.parse(XMLGregorianCalendarImpl.java:2898)
    at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl.<init>(XMLGregorianCalendarImpl.java:478)
    at org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl.newXMLGregorianCalendar(DatatypeFactoryImpl.java:230)
    at __redirected.__DatatypeFactory.newXMLGregorianCalendar(__DatatypeFactory.java:132)
    at javax.xml.bind.DatatypeConverterImpl.parseDate(DatatypeConverterImpl.java:519)
    at javax.xml.bind.DatatypeConverter.parseDate(DatatypeConverter.java:431)
    at eu.europa.ec.my.custom.package.model.mapper.XsdDateTimeConverter.unmarshal(XsdDateTimeConverter.java:23)

我的 XsdDateTimeConverter class 看起来像这样:

public class XsdDateTimeConverter {

    public static Date unmarshal(String dateTime) {
        return DatatypeConverter.parseDate(dateTime).getTime();
    }

    public static String marshalDate(Date date) {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return DatatypeConverter.printDate(calendar);
    }

    public static String marshalDateTime(Date dateTime) {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateTime);
        return DatatypeConverter.printDateTime(calendar);
    }
}

我的 postgres 数据库中的解析日期如下所示:

move_timestamp timestamp(6) with time zone

2019-02-28 12:17:46.279+00

在我的休息方法中,我使用这样的 ObjectMapper

MyCustomResponseDto responseDto = customService.getCustomResponseDto(query);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
String strValue = mapper.writeValueAsString(responseDto);
return Response.ok(strValue).build();

我想我真正想要的是这个日期的正确模式。我可以进入此页面:http://www.sdfonlinetester.info/ 并输入我的模式(例如 yyyy-MM-dd'T'HH:mm:ss.SSSZ),它会为您提供该模式的实际日期输出。我需要反过来。我想输入我的日期,它会给我正确的模式。

您可以试试下面的代码

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ENGLISH); String lastmod = format.format(new Date());

为自己省去一大堆麻烦,并以毫秒为单位节省大纪元时间。仅在 UI 中解析和呈现日期。人类调度的情况很少需要计算机知道小时、天、周、月、年...但是及时保存瞬间只是 'long'.

tl;博士

OffsetDateTime.parse( 
    "2019-02-28T12:17:46.279+0000" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" , Locale.ROOT )
)

java.time

您使用的 Calendar class 多年前被 java.time classes 取代。

ISO 8601

您的输入字符串采用标准 ISO 8601 格式,专为人类可读、机器可解析的日期时间值文本表示而设计。这是一件好事。

当 parsing/generating 字符串时,java.time classes 默认使用 ISO 8601 格式。

OffsetDateTime

应该能够简单地用OffsetDateTime解析。

OffsetDateTime.parse( "2019-02-28T12:17:46.279+0000" )

…但不幸的是,从偏移量 (+00:00) 中省略了可选的 COLON 字符是一个问题。 OffsetDateTime class 有一个小错误,它拒绝在没有该字符的情况下进行解析。该错误已讨论 and

ISO 8601 标准允许没有冒号,但实际上您应该始终包含冒号。 OffsetDateTime class 并不孤单;我已经看到其他库在缺少冒号或填充零时会中断。我建议要求您的数据发布者使用完整的 ISO 8601 格式,包括冒号。

OffsetDateTime 错误的解决方法是明确定义 DateTimeFormatter

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" , Locale.ROOT ) ;

然后解析。

String input = "2019-02-28T12:17:46.279+0000" ;
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;

要生成完全标准的 ISO 8601 格式的文本,只需调用 toString

String output = odt.toString() ;

看到这个code run live at IdeOne.com

output: 2019-02-28T12:17:46.279Z

最后的Z表示UTC,即+0000+00:00。发音为“祖鲁语”。非常常用,比数字偏移更易读。

如果您想要与输入相同的输出格式,请使用相同的 DateTimeFormatter

String output = odt.format( f ) ;