使用 Java 8 的给定日期(UTC 日期)和当前日期之间的天数差异

Difference between give date (UTC date) and current date in days using Java 8

我的方法的输入将是 String,其中包含 UTC 日期。我需要将输入日期与当前日期和时间进行比较,并检查两个日期之间的差异。结果应该以天为单位。

我尝试了以下但没有成功。

String dateString = "2019-06-18T16:23:41.575 UTC";
final DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS 'UTC'").withZone(ZoneId.of("UTC"));
OffsetDateTime parsedDate  = OffsetDateTime.parse(dateString, formatter1);
System.out.println("======================:"+parsedDate.format(formatter1));


OffsetDateTime currentUTC = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println("Until (with crono): " + parsedDate.until(currentUTC, ChronoUnit.DAYS));

我需要 int 中的结果(即天数)。

OffsetDateTime parsedDate = OffsetDateTime.parse(dateString, formatter1); 抛出异常,堆栈跟踪如下:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2019-06-18T16:23:41.575 UTC' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {InstantSeconds=1560875021},ISO,UTC resolved to 2019-06-18T16:23:41.575 of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1959)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1894)
    at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at thiagarajanramanathan.misc.App.main(App.java:86)
Caused by: java.time.DateTimeException: Unable to obtain OffsetDateTime from TemporalAccessor: {InstantSeconds=1560875021},ISO,UTC resolved to 2019-06-18T16:23:41.575 of type java.time.format.Parsed
    at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:370)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1890)
    ... 3 more
Caused by: java.time.DateTimeException: Unable to obtain ZoneOffset from TemporalAccessor: {InstantSeconds=1560875021},ISO,UTC resolved to 2019-06-18T16:23:41.575 of type java.time.format.Parsed
    at java.base/java.time.ZoneOffset.from(ZoneOffset.java:348)
    at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:359)
    ... 5 more

正如您从这个帖子中看到的那样:
我更改了以下几行:

//OffsetDateTime parsedDate  = OffsetDateTime.parse(dateString, formatter1);
ZonedDateTime parsedDate = ZonedDateTime.parse(dateString, formatter1);

当你的代码运行修改后,我可以得到以下结果

对于“2019-06-18T16:23:41.575 UTC”:

======================:2019-06-17T16:23:41.575 UTC
Until (with crono): 0

因为还不到 24 小时,所以 returns 0

对于“2019-06-17T16:23:41.575 UTC”:

======================:2019-06-17T16:23:41.575 UTC
Until (with crono): 1

同样,由于超过 24 小时但不到 2 天,returns 1.

我想这就是你想要的。请尝试一下,让我知道这是否适合您。

正在解析

如果您的输入符合 ISO 8601 标准,我会简化解析。

String input = "2019-06-18T16:23:41.575 UTC".replace( " UTC", "Z" ) ;
Instant instant = Instant.parse( input ) ;

以 24 小时为单位的天数

如果您对已用天数的定义是 24 小时时间块,请使用 Duration

Duration d = Duration.between( instant , Instant.now() ;
long days = d.toDays() ;

根据日历的天数

如果您想要在日历上看到经过的天数,意思是日期而不是 24 小时时间块,您必须指定时区。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

提取日期。

LocalDate start = zdt.toLocalDate() ;
LocalDate stop = now.toLocalDate() ;
long days = ChronoUnit.DAYS.between( start , stop ) ;

时区与时差的区别

你已经得到了两个很好的答案。您正在触及 java.time 中一个有趣且有点棘手的部分,所以我也想做出自己的贡献。我的关键点是 时区和 UTC 偏移量不相同 。要获得 OffsetDateTime,您需要一个偏移量。您通过格式化程序上的调用 .withZone(ZoneId.of("UTC")) 提供时区,但这对您没有帮助。是的,您和我都知道 UTC 是所有偏移量的基础,因此它本身将偏移量定义为 0。但是 Java 没有从您的代码中发现这一点。

我承认我惊讶地发现以下简单更改足以让您的代码在 Java 9:

上运行
    final DateTimeFormatter formatter1
            = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS 'UTC'")
                    .withZone(ZoneOffset.UTC);

但是在 Java 8 我仍然遇到与以前相同的异常。我在 Java 9.0.4 上得到的输出是:

======================:2019-06-18T16:23:41.575 UTC
Until (with crono): 0

唯一的变化是我现在将 ZoneOffset 而不是 ZoneId 对象传递给 withZone(这是可能的,因为 ZoneOffsetZoneId).

一种适用于 Java 8 的格式器也是我们提供默认偏移量的格式器。为此,我们需要 DateTimeFormatterBuilder:

    final DateTimeFormatter formatter1 = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendLiteral(" UTC")
            .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
            .toFormatter();

另一个可能更简单的选择是首先解析为 LocalDateTime(既不需要偏移量也不需要时区),然后通过调用 .atOffset(ZoneOffset.UTC) 转换为 OffsetDateTime