如何在 Android 的另一个时区获取一天的开始时间和结束时间

How to get start time and end time of a day in another timezone in Android

我的日期格式为:YYYY-MM-DD

所需的输出格式为: "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

我想获取 ISO 格式的日期作为一天的开始时间(从 12:00AM 开始)和一天的结束时间(在 11:59PM 结束)在 America/Chicago时区。

例如。对于日期:2020-06-08(6 月 8 日),转换后的最终输出如下:

日期的开始时间:2020-06-08T05:00:00.000Z

一天的结束时间为日期:2020-06-09T04:59:59.999Z

如果有人对此有任何线索,请在这里帮助我。

答案: http://m.uploadedit.com/bltc/1591511729781.txt

java.time 和 ThreeTenABP

我建议使用 java.time,现代 Java 日期和时间 API,用于此类日期和时间数学运算。

    ZoneId zone = ZoneId.of("America/Chicago");

    String dateString = "2020-06-08";
    LocalDate date = LocalDate.parse(dateString);
    Instant startOfDay = date.atStartOfDay(zone).toInstant();
    Instant endOfDay = date.plusDays(1).atStartOfDay(zone).toInstant();

    System.out.println("The day is from " + startOfDay + " (inclusive) to " + endOfDay + " (exclusive)");

输出为:

The day is from 2020-06-08T05:00:00Z (inclusive) to 2020-06-09T05:00:00Z (exclusive)

为了不排除当天的最后一毫秒,我们需要将这一天算作持续到第二天的第一时刻。如果您确实坚持要减去一毫秒或仅减去一纳秒,当然,这取决于您。例如:

    Instant endOfDay = date.plusDays(1).atStartOfDay(zone).minusNanos(1).toInstant();

The day is from 2020-06-08T05:00:00Z (inclusive) to 2020-06-09T04:59:59.999999999Z (inclusive and 1 nano more)

编辑: 如何在输出中打印毫秒数?你很可能不需要那个。您要求的格式是国际标准 ISO 8601(请参阅底部的 link)。在 ISO 8601 中,秒的小数部分是可选的,将其省略意味着 0。因此任何需要 ISO 8601 的 API 都应该接受上述内容。只有在没有的情况下,正确的解决方案才是使用格式化程序。在这种情况下,我们需要将时间显式转换为 UTC:

    ZoneId zone = ZoneId.of("America/Chicago");
    DateTimeFormatter formatterWithMillis = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");

    String dateString = "2020-06-08";
    LocalDate date = LocalDate.parse(dateString);
    OffsetDateTime startOfDay = date.atStartOfDay(zone)
            .toOffsetDateTime()
            .withOffsetSameInstant(ZoneOffset.UTC);
    OffsetDateTime endOfDay = date.plusDays(1)
            .atStartOfDay(zone)
            .toOffsetDateTime()
            .withOffsetSameInstant(ZoneOffset.UTC);

    String startString = startOfDay.format(formatterWithMillis);
    String endString = endOfDay.format(formatterWithMillis);
    System.out.println("The day is from " + startString + " (inclusive) to " + endString + " (exclusive)");

The day is from 2020-06-08T05:00:00.000Z (inclusive) to 2020-06-09T05:00:00.000Z (exclusive)

或者像以前一样从结束时间减去纳秒后:

    OffsetDateTime endOfDay = date.plusDays(1)
            .atStartOfDay(zone)
            .minusNanos(1)
            .toOffsetDateTime()
            .withOffsetSameInstant(ZoneOffset.UTC);

The day is from 2020-06-08T05:00:00.000Z (inclusive) to 2020-06-09T04:59:59.999Z (inclusive and 1 nano more)

(由于时间被截断为整毫秒,因此 1 nano more 没有任何意义,但我认为这不是重点。)

问题:java.time 不需要 Android API 26 级吗?

java.time 在新旧 Android 设备上都能很好地工作。它只需要至少 Java 6.

  • 在 Java 8 和更新的 Android 设备上(从 API 级别 26)内置现代 API。
  • 在非Android Java 6 和 7 中得到 ThreeTen Backport,现代 类 的 backport(ThreeTen for JSR 310;参见 links在底部)。
  • 在(较旧的)Android 使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。并确保使用子包从 org.threeten.bp 导入日期和时间 类。

But don't we have any other option apart from switching to ThreeTenBP Library?

如果您坚持,我想可以找到使用 CalendarDateSimpleDateFormat 的方法。那些 类 设计不佳且早已过时,所以根据我所知道和不知道的,我更喜欢 ThreeTenABP。

链接

已更新:

    ZoneId zoneId = ZoneId.of("America/Chicago");
    LocalDate localDate = LocalDate.parse("2020-06-08");
    DateTimeFormatter newPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(zoneId);
    Instant startOfDay = localDate.atStartOfDay(zoneId).toInstant();
    Instant endOfDay = LocalDateTime.of(localDate, LocalTime.MAX).atZone(zoneId).toInstant().truncatedTo(ChronoUnit.MILLIS);
    System.out.println(startOfDay);
    System.out.println(endOfDay);

根据我的经历,小数 000 不会出现在其中,但是可以肯定的是,如果没有毫秒的小数部分,那么它就是 000。我无法弄清楚如何带来这个格式化时。 如果您找到了某些内容,请添加其他内容,您可以通过将 startDate 转换为 String 然后将 000 附加到它来完成此操作。

结果

    2020-06-08T05:00:00Z
    2020-06-09T04:59:59.999Z