首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java XMLGregorianCalendar格式

Java XMLGregorianCalendar格式
EN

Stack Overflow用户
提问于 2018-04-02 11:13:34
回答 3查看 182关注 0票数 0

我目前被XMLGregorianCalendar格式化问题困扰,想向你的java专家寻求帮助。通过从其他系统调用函数,我在网页上显示了一个数据对象,其中"SUBMIT_DATE":1516032000000和"SUBMIT_TIME":36895000 (都具有返回类型XMLGregorianCalendar)。在这种情况下,我如何知道人类可读的正确日期和时间?

感谢您的时间和帮助。

EN

回答 3

Stack Overflow用户

发布于 2018-04-02 14:04:59

澄清后更新

代码语言:javascript
复制
    // We first need to check that the fields we need are defined
    if (submitDate.getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
        throw new IllegalStateException("No time zone defined in submit date " + submitDate);
    }
    if (submitDate.getYear() == DatatypeConstants.FIELD_UNDEFINED
            || submitDate.getMonth() == DatatypeConstants.FIELD_UNDEFINED
            || submitDate.getDay() == DatatypeConstants.FIELD_UNDEFINED) {
        throw new IllegalStateException("Date not defined in submit date " + submitDate);
    }
    if (submitTime.getHour() == DatatypeConstants.FIELD_UNDEFINED
            || submitTime.getMinute() == DatatypeConstants.FIELD_UNDEFINED
            || submitTime.getSecond() == DatatypeConstants.FIELD_UNDEFINED) {
        throw new IllegalStateException("Time of day not defined in submit time " + submitTime);
    }
    if (submitTime.getTimezone() != DatatypeConstants.FIELD_UNDEFINED
            && submitTime.getTimezone() != submitDate.getTimezone()) {
        throw new IllegalStateException("Conflicting offsets " + submitDate.getTimezone() 
                + " and " + submitTime.getTimezone() + " minutes");
    }

    // then format into a human readable string
    final ZoneId userZone = ZoneId.of("Asia/Taipei");
    final Locale userLocale = Locale.forLanguageTag("zh-TW");
    DateTimeFormatter localizedFormatter = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.LONG)
            .withLocale(userLocale);
    ZonedDateTime dateTime = submitDate.toGregorianCalendar()
            .toZonedDateTime()
            .with(LocalTime.of(submitTime.getHour(), submitTime.getMinute(), submitTime.getSecond()))
            .withZoneSameInstant(userZone);
    String humanReadableDateTime = dateTime.format(localizedFormatter);
    System.out.println(humanReadableDateTime);

这将打印:

2018年1月16日上午10時14分55秒

我假设submitDatesubmitTime是您从远程系统接收的复杂对象中获得的XMLGregorianCalendar对象。我进一步假设您可以要求日期包含UTC偏移量。尽管该方法名为getTimezone,但它真正返回的不是时区,而是从协调世界时(或格林尼治标准时间)以分钟为单位的偏移量。这四个if语句中的大量检查是必要的,因为XMLGregorianCalendar非常灵活,可以定义哪些字段,哪些没有。

要以适合用户受众的格式显示日期和时间,您需要知道该受众的时区和地区。一旦你知道了这些,请在上面的代码片段中填写它们。如果您信任JVM的设置,您可以使用ZoneId.systemDefault()和/或Locale.getDefault(Locale.Category.FORMAT)。您还可以在格式样式FULLLONGMEDIUMSHORT之间进行选择。

如果您没有收到偏移量,则需要依赖已经处于用户偏移量的日期和时间。一方面它更简单,另一方面它更脆弱,因为如果日期和时间是在用户预期之外的另一个偏移量上给出的,他/她将收到不正确的信息,这比根本没有收到任何信息更糟糕。首先检查是否确实没有偏移量:

代码语言:javascript
复制
    if (submitDate.getTimezone() != DatatypeConstants.FIELD_UNDEFINED
            || submitTime.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
        throw new IllegalStateException("Unexpected offset");
    }

还要检查是否定义了必填字段,这与前面的相同。然后创建一个LocalDateTime对象并对其进行格式化:

代码语言:javascript
复制
    LocalDateTime dateTime = LocalDateTime.of(
            submitDate.getYear(), submitDate.getMonth(), submitDate.getDay(), 
            submitTime.getHour(), submitTime.getMinute(), submitTime.getSecond());
    String humanReadableDateTime = dateTime.format(localizedFormatter);

我得到了和上面一样的结果。

原始答案

代码语言:javascript
复制
    final ZoneId userZone = ZoneId.of("Asia/Taipei");
    final Locale userLocale = Locale.forLanguageTag("zh-TW");
    ZonedDateTime submitDateTime 
            = Instant.ofEpochMilli(submitDate + submitTime).atZone(userZone);
    DateTimeFormatter localizedFormatter = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.LONG)
            .withLocale(userLocale);
    String humanReadableDateTime = submitDateTime.format(localizedFormatter);
    System.out.println(humanReadableDateTime);

这是打印

2018年1月16日上午10時14分55秒

要以适合用户受众的格式显示日期和时间,您需要知道该受众的时区和地区。一旦您知道了这些,请在上面代码片段的前两行中填写它们。如果您信任计算机的设置,您可以使用ZoneId.systemDefault()和/或Locale.getDefault(Locale.Category.FORMAT)。您还可以在格式样式FULLLONGMEDIUMSHORT之间进行选择。为此,我认为您可以忽略返回类型为XMLGregorianCalendar的信息。

作为another answer中的@user unknown,我假设您只需将两个数值相加即可。第一个几乎可以肯定地表示自纪元以来的毫秒,总和可能也是如此。那么为什么它们被作为两个值传递,而不只是一个呢?我最好的猜测是,对于任何只需要日期而不是一天中的时间的客户端,它们会分别传递日期。日期值在时区的午夜偏移量+08:00,这将与中国,菲律宾,马来西亚和其他十几个时区一致。

如果您得到的不是数字,而是两个XMLGregorianCalendar对象,那么获取日期和时间就是另一回事了,但是您仍然可以使用相同的方法来格式化它们。

票数 2
EN

Stack Overflow用户

发布于 2018-04-02 11:54:22

代码语言:javascript
复制
    final GregorianCalendar calendar = new GregorianCalendar();
    calendar.setTimeInMillis(date);
    return DatatypeFactory.newInstance().newXMLGregorianCalendar(
        calendar);

这应该行得通..传递你的毫秒数

票数 1
EN

Stack Overflow用户

发布于 2018-04-02 11:44:06

您的输入看起来就像是没有时间的日期(毫秒)和没有日期的时间(毫秒)。

如果将这两个值除以1000:

代码语言:javascript
复制
date -d @1516032000
Mo 15. Jan 17:00:00 CET 2018
date -d @36895
Do 1. Jan 11:14:55 CET 1970

但为什么是17:00:00?也许是时区问题。

以下是汇总结果:

代码语言:javascript
复制
date -d @$((1516032000+36895))
Di 16. Jan 03:14:55 CET 2018

Java的各种日期/时间格式都有一些方法,这些方法从epoch (1.1.1970)开始接受一个很长的秒数参数来设置时间。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49604838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档