【问题标题】:Add a Java 8 ISO 8601 time duration expression to java.util.Date将 Java 8 ISO 8601 持续时间表达式添加到 java.util.Date
【发布时间】:2018-12-09 13:18:15
【问题描述】:

我有一个类似"PT20.345S""P2DT3H4M" 等的表达式,如此处所述https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-

如何解析这个,将其添加到当前时间并获得java.util.Date 对象?

都不行:

Date d1 = Date.from(LocalDateTime.now().plus(Duration.parse(_expression)));
Date d2 = Date.from(Duration.parse(_expression).addTo(LocalDateTime.now()));

【问题讨论】:

  • 仅供参考:(A) 尽量避免使用 java.util.Date 类。几年前完全被java.time.Instant 类取代。 (B) 当你指的是一个实际的时刻,时间线上的一个特定点时,千万不要使用LocalDateTime。使用InstantZonedDateTimeOffsetDateTime

标签: java date duration java-time iso8601


【解决方案1】:
Duration amountToAdd = Duration.parse("PT20.345S");  // Represent a span of time. Here, about twenty and a third seconds.
Instant now = Instant.now() ;                        // Capture the current moment in UTC.
Instant otherMoment = now.plus(amountToAdd);         // Add the span-of-time to the current moment, for a moment in the future (or in the past if the duration is negative).
String output = otherMoment.toString():              // Generate a String in standard ISO 8601 format.

2018-06-30T19:34:47Z

从现代 java.time 类转换为旧类。

Date date1 = Date.from(otherMoment);
System.out.println(date1);

我刚刚在欧洲/哥本哈根时区跑步:

2018 年 6 月 30 日星期六 21:34:47 CEST

如果我使用您的其他示例持续时间字符串 P2DT3H4M,我得到:

2018 年 7 月 3 日星期二 00:38:26 CEST

或者如果你喜欢单线:

    Date date1 = Date.from(Instant.now().plus(Duration.parse("PT20.345S")));

java.util.Date 类早已过时,因此理想情况下您不应该拥有一个。如果您仍然需要一个,通常是对于您现在无法更改或不想更改的遗留 API,在使用现代 Java 日期和时间 API java.time 执行尽可能多的逻辑时,您的想法是正确的,最后只转换为DateDate 在现代世界中的近亲是InstantInstantDate 之间存在直接转换,这就是我使用这个类的原因。 Instant 也很可爱,不受区域偏移和时区的影响。

【讨论】:

    【解决方案2】:

    在您的代码中,如果您将LocalDateTime 转换为InstantZoneOffset(例如UTC,或您的系统默认使用ZoneOffset.systemDefault()),则第一个解决方案应该可以工作,如下所示:

    Date d1 = Date.from(LocalDateTime.now().plus(Duration.parse(_expression)).toInstant(OffsetDateTime.now().getOffset());
    

    但是LocalDateTime在这种情况下是错误使用的,因为它不代表一个时刻,不是时间轴上的一个点

    来自javadoc

    此类不存储或表示时区。相反,它是对日期的描述,用于生日,结合挂钟上的当地时间。如果没有偏移或时区等附加信息,它就不能代表时间线上的瞬间。

    但是,Instant 是 UTC 时间线上的一个时刻

    此类模拟时间线上的单个瞬时点。这可能用于在应用程序中记录事件时间戳。

    因此,如果您使用 Instant,则无论时区如何,您都可以准确地知道所指的时间点。由于您要处理业务逻辑,例如将时间量添加到当前时间并转换为日期,因此这是一个方便使用的类。

     Date date1 = Date.from(Instant.now().plus(Duration.parse("PT20.345S")));
    

    【讨论】:

    • 谢谢!但是为什么ZoneOffset.systemDefault() 返回一个 ZoneId 对象呢?这是我避免使用新 api 的原因之一...
    • 目标是获取 Date 对象加上指定的时间量。如果我使用 ZoneOffset.UTC,我会实现它还是需要查看如何获取默认时区的 ZoneOffset?
    • 首先,抱歉我没有检查ZoneOffset.systemDefault() return ZoneId。然后你可以使用OffsetDateTime.now().getOffset() 来获取默认的系统偏移量(参考:stackoverflow.com/questions/41427384/…
    • LocalDateTime 是在这里使用的完全错误的类。它确实代表一个时刻,它不是时间线上的一个点。请参阅 Ole V.V. 的 correct Answer
    • @fedd 这个:OffsetDateTime.now().getOffset() 和这个:ZoneOffset.systemDefault() 具有相同的效果。我建议第二个:更短,你的意图对读者来说更明显。仅供参考:与 UTC 的偏移量只是几个小时-分钟-秒,仅此而已。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。比如北美西海岸的大部分人America/Los_Angeles,半年使用-08:00(比UTC晚八小时)的偏移量,另一半年使用-07:00的偏移量.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多