以 ISO 8601 格式生成昨天日期时间的字符串

Generate string of yesterday’s date-time in ISO 8601 format

在 Android 中,我使用 java.util.Calendar 获取格式为 yyyy-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.

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

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

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

您使用 hh 表示小时数,但显示的是 AM/PM 的小时数。

这些是相关符号(来自SimpleDateFormat

  • H 一天中的小时 (0-23)
  • k 一天中的小时 (1-24)
  • K 小时 am/pm (0-11)
  • h 小时 am/pm (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);
cal.add(Calendar.DAY_OF_YEAR, -1);

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

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

时区

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

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

运行刚刚呢,结果是

2017-05-30T00:00:00Z

您可以使用更简单的代码代替代码段的最后一行:

    .toString();

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

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

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

ThreeTenABP 项目中的 Android 进一步调整了该反向端口。