【问题标题】:Generate string of yesterday’s date-time in ISO 8601 format以 ISO 8601 格式生成昨天的日期时间字符串
【发布时间】:2017-05-31 06:56:45
【问题描述】:

在 Android 中,我使用java.util.Calendaryyyy-MM-dd'T'hh:mm:ss'Z' 格式获取昨天的日期。例如,如果今天是31 May 2017,我想将昨天的日期设为2017-05-30T00:00:00Z

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

// Date End = yesterday
calendar.add(Calendar.DATE, -1);
Date dateEnd = calendar.getTime();

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
this.dateEndStr = formatter.format(dateEnd);

我期望输出为2017-05-30T00:00:00Z。但它给了我2017-05-30T12:00:00Z

这里有什么问题?它与时区有关吗?我的时区是GMT/UTC + 08:00 hour

【问题讨论】:

标签: java android date calendar simpledateformat


【解决方案1】:

我可能回答的比你问的要多,但现在你问了,为什么不把它全部拿走?我发现您的代码有两三处错误。 another answer 中的 bowmore 已经谈到了所有这三个,但我认为其中一些可以更清楚一点:

  1. 是的,第一个也是最严重的是时区相关的。您需要决定,并且应该在代码中明确说明您使用哪个时区。在区域偏移 +08:00 的时间将 Z 作为时区是不正确的。 Z 代表祖鲁时间,UTC 的另一个名称。
  2. 在您的格式模式中,您应该使用大写 HH 表示一天中的小时。
  3. 原则上,您应该更喜欢现代日期和时间类,但对于这种情况至少。有了这些,您将无法犯旧式SimpleDateFormat 所犯的错误。

时区

时区对您的任务至关重要。您需要确定昨天的日期是 UTC(如您请求的输出所示)、GMT/UTC + 08:00 还是 JVM 的当前时区(可以在程序运行时随时更改)。这个 sn-p 使用 UTC:

this.yesterdayAtStartOfDay = LocalDate.now(ZoneOffset.UTC)
    .minusDays(1)
    .atStartOfDay(ZoneOffset.UTC)
    .format(DateTimeFormatter.ISO_INSTANT);

刚才运行,结果是

2017-05-30T00:00:00Z

代替sn-p的最后一行,你可以使用更简单的:

    .toString();

这给出了相同的结果,因为atStartOfDay() 给出了带有时区 Z 的 ZonedDateTime,而它的 toString() 方法给出了您请求的 ISO 8601 字符串。

如果您想在另一个时区显示昨天的日期,请在 sn-p 的第一行(并且仅在第一行)使用 ZoneOffset.ofHours(8)ZoneId.of("Asia/Hong_Kong")ZoneId.systemDefault() 作为时区。

如果您使用的是 Java 6 或 7,要使用现代日期和时间类,您需要获取 the ThreeTen-Backport library。尽管在引入外部依赖项之前我总是三思而后行,但我还是热情地推荐这个来完成你的任务。

该反向端口在ThreeTenABP 项目中进一步适用于Android。

【讨论】:

    【解决方案2】:

    这只是您的SimpleDateFormat 中的一个错误。

    您使用hh 表示小时,但它显示的是基于一小时的上午/下午。

    这些是相关符号(来自SimpleDateFormat

    • H一天中的小时(0-23)
    • k一天中的小时(1-24)
    • K 上午/下午 (0-11) 小时
    • h 上午/下午 (1-12) 小时

    你想要这个:"yyyy-MM-dd'T'HH:mm:ss'Z'"

    备注

    您说您的时区是 +08:00 小时,并且您使用该时区计算日期,但是您将其格式化为就像它在祖鲁时区(偏移量为 +00:00)中一样

    奖金

    在 Java 8 中,所有这些日历操作都消失了:

    ZonedDateTime yesterday = ZonedDateTime.now().with(ChronoField.NANO_OF_DAY, 0).minusDays(1);
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
    dateEndStr = formatter.format(dateEnd);
    

    【讨论】:

    • 谢谢! HH 解决了我的问题:D
    • 在时区偏移 +8 的时间将 Z 作为时区是不正确的,这显然是正确的。我也同意应该更喜欢 Java 8 解决方案,它更清晰、更方便。所需的格式是 ISO 8601,Java 8 中的默认格式,因此您可以使用Instant.toString()DateTimeFormatter.ISO_INSTANT,这比构建自己的格式化程序更简单、更清晰。而且,正如问题所示,更不容易出错。 :-)
    • Java 8 日期和时间类也是backported to Java 6 and 7。你真的没有什么理由不喜欢他们来完成这项任务。
    【解决方案3】:
    cal.add(Calendar.DAY_OF_YEAR, -1);
    

    【讨论】:

      【解决方案4】:

      要减去天数,您应该使用:

      Calendar calendar = Calendar.getInstance();
      calendar.add(Calendar.DAY_OF_MONTH, -5);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-17
        • 1970-01-01
        • 2018-06-26
        • 2019-02-27
        • 2018-02-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多