【问题标题】:SOAP Web Service parsing Date from String returning d-1 valueSOAP Web 服务从返回 d-1 值的字符串中解析日期
【发布时间】:2018-02-07 10:03:15
【问题描述】:

我正在使用org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDate(StringDate) 将输入字符串日期从 XML 解析为 JAVA 日期。但是我得到了一个具有第 1 天值的 Date 对象。

例如

<birth>1939-11-19+01:00</birth>

我想忽略偏移量。我只想要日期,所以无论偏移量是多少,我都应该得到

Sun Nov 19 00:00:00 CET 1939

但我确实得到了:

Sat Nov 18 23:00:00 CET 1939

问题在于日期的时间偏移。我试图通过忽略时间偏移来修复它,但这没有用。我正在使用 java 6(约束项目)。有什么想法吗?

我对最小、完整和可验证示例的最佳尝试:

public static Date parse(final String str) {
    Calendar c = DatatypeConverter.parseDateTime(str);
    System.out.println(str + "\t" + c.getTime().getTime() / 1000);
    return c.getTime();
}

【问题讨论】:

  • 如果您只想要日期,与链接的问题相比,您可以简单一点:LocalDate.parse("1939-11-19+01:00", DateTimeFormatter.ISO_OFFSET_DATE)
  • 我有使用 java 6 的限制
  • 可怜的你。 :-) 您可以将ThreeTen Backport 添加到您的项目中吗?然后它也可以在 Java 6 中工作。
  • 存在一些已知问题。 Hijrah 日历系统不起作用。格式化和解析通常取决于仅在 Java SE 8 中可用的数据。区域 id 和文本解析的功能要弱得多。

标签: xml date timezone cxf java-6


【解决方案1】:

java.time

    String birth = "1939-11-19+01:00";
    LocalDate date = LocalDate.parse(birth, DateTimeFormatter.ISO_OFFSET_DATE);
    System.out.println(date);

打印出来

1939-11-19

java.time.LocalDate 是一个没有时间的日期,因此这完全符合您的要求。同时java.util.Date 和朋友们早已过时并且被证明设计不佳。 java.time,现代 Java 日期和时间 API,使用起来非常好用。所以我的第一个建议是你到此为止。

如果您确实需要 Date,例如对于旧版 API,请首先意识到尽管名称不代表日期。它代表一个时间点,在那个时间点,日期不会在任何地方都相同。如您所知,这可能会导致您的问题:parseDateparseDateTime 将您的字符串解析为 00:00 在相关日期与 UTC 的指定偏移量处。此时,您所在时区的日期可能并不相同,因此当您打印得到的Date,从而调用其toString 方法时,您可能会得到不同的日期。我知道您希望在您自己的时区中使用 0:00 的时间(CET,可能是中欧时间,这又是几个不同时区的名称,这些时区可能在 1939 年该日期的偏移量为 0 或 +01;您观察到的结果在欧洲/巴黎、非洲/休达、欧洲/安道尔、欧洲/马德里和欧洲/摩纳哥时区是有意义的,所有这些时区的偏移量都为 0)。转换:

    Date oldfashionedDateObject 
            = Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    System.out.println(oldfashionedDateObject);

这个打印出来的

Sun Nov 19 00:00:00 CET 1939

我将我的时区设置为 America/New_York 和 Europe/Moscow 进行测试,始终得到Sun Nov 19 00:00:00,仅在不同的时区ESTMSK

Java 6 和 ThreeTen 向后移植

我知道您必须使用 Java 6。java.time 已在 ThreeTen Backport 中向后移植到 Java 6 和 7。所以从底部的链接中获取它并将其添加到您的项目中,上面的代码将起作用,只是转换发生的方式略有不同:

    Date oldfashionedDateObject
            = DateTimeUtils.toDate(date.atStartOfDay(ZoneId.systemDefault()).toInstant());

您无需重写所有代码即可使用 ThreeTen Backport,尤其是在某些部分您不信任现代 API 以您想要的方式运行时。上面的 sn-p 可以和你已有的代码很好的共存。

真正的老式方式

如果您真的坚持,我可以找到使用DatatypeConverterCalendar 获得您想要的Date 的方法:

    Calendar calWithParsedOffset = DatatypeConverter.parseDate(birth);
    Calendar calWithMyTimeZone = Calendar.getInstance(TimeZone.getDefault());
    calWithMyTimeZone.clear();
    calWithMyTimeZone.set(calWithParsedOffset.get(Calendar.YEAR),
            calWithParsedOffset.get(Calendar.MONTH),
            calWithParsedOffset.get(Calendar.DAY_OF_MONTH));
    Date oldfashionedDateObject = calWithMyTimeZone.getTime();
    System.out.println(oldfashionedDateObject);

我们不能只改变解析得到的Calendar 的偏移量或时区,因为这不会改变它的时间点,因此也不会改变我们得到的Date 对象。相反,我们需要将不同的Calendar 对象设置为第一个Calendar 的年、月和日。对 clear() 的调用将小时、分钟、秒和毫秒设置为 0。这个 sn-p 也已经在我的 JVM 的时区设置为 America/New_York 和 Europe/Moscow 的情况下进行了测试。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 2021-09-11
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多