【问题标题】:Setting future date in Java 8在 Java 8 中设置未来日期
【发布时间】:2018-12-25 12:34:09
【问题描述】:

在 Joda 我们有 setCurrentMillisFixed 方法,可以用来设置未来的日期 在我的一个测试用例中,我将 DateTime (joda) 参数传递给 当前系统时间: DateTime created = new DateTime() DateTimeUtils.setCurrentMillisSystem(created.toInstant().toEpochMilli()););

在 Java 8 中,我正在尝试: 我通过 ZonedDateTime 而不是 DateTime,

我尝试将日期设置如下:

ZonedDateTime.now(Clock.fixed(Instant.now().plusMillis(created.toInstant().toEpochMilli()),ZoneId.systemDefault()));

但是很多测试用例都失败了,我猜这与日期的设置方式有关。

有什么建议吗?找不到任何有用的代码,

【问题讨论】:

  • 如果您提供一些有关测试用例失败原因的信息会有所帮助,或者您是否也要求我们猜测?
  • 我也在尝试调试测试失败的原因,代码库非常庞大,我相信代码库中的某个地方,未设置未来日期,我将 chnge 恢复为 dateTime,它开始了再次工作,只是想知道设置未来日期的正确方法,如果我们要设置确切的日期,我知道DateTimeUtils.setCurrentMillisFixed(new DateTime(1900, 1, 13, 0, 0).getMillis()); - 我们可以替换为Clock clock = Clock.fixed(LocalDateTime.of(1900, 1, 13, 0, 0).toInstant(UTC), systemDefault())

标签: java-8 zoneddatetime


【解决方案1】:

2066 年?

我怀疑你设定了一个意想不到的时刻,大约 50 年后。

让我们解压缩您的代码。

ZonedDateTime.now(                    // Represents a moment adjusted into a time zone. 
    Clock.fixed(
        Instant.now()                 // Get current moment. Actually a count of nanoseconds since 1970-01-01T00:000Z. That is 48 years, about 5 decades worth of nanoseconds.
               .plusMillis(           // Adding some more milliseconds, for a moment in the future, later than now.   
            created.toInstant()       // Accessing some stored moment. Presumably a contemporary date-time.
                   .toEpochMilli()) , // Getting the count of milliseconds since 1970-01-01T00:000Z, another 5 decades or so of time.
            ZoneId.systemDefault()    // Getting the JVM’s current default time zone. To be assigned to our resulting `ZonedDateTime` object.
        )
)

因此,您从大约 5 个数十纳秒开始。然后,大概再增加大约 5 个数十毫秒。所以你最终得到了一个未来 50 年的日期,大约 2066 年。这是你打算测试的值吗?

2066 ≈ 2018 + (时间从 1970 年到 2018 年左右的某个时刻)

我们可以试试那个代码,看看结果。

ZonedDateTime created = ZonedDateTime.of( 2018 , 1 , 23 , 12 , 34 , 56, 0 , ZoneId.systemDefault()); // 2018-01-23T12:34:56 in America/Los_Angeles.

ZonedDateTime zdt =     ZonedDateTime.now(                    // Represents a moment adjusted into a time zone.
    Clock.fixed(
        Instant.now()                 // Get current moment. Actually a count of nanoseconds since 1970-01-01T00:000Z. That is 48 years, about 5 decades worth of nanoseconds.
            .plusMillis(           // Adding some more milliseconds, for a moment in the future, later than now.
                created.toInstant()       // Accessing some stored moment. Presumably a contemporary date-time.
                    .toEpochMilli()) , // Getting the count of milliseconds since 1970-01-01T00:000Z, another 5 decades or so of time.
        ZoneId.systemDefault()    // Getting the JVM’s current default time zone. To be assigned to our resulting `ZonedDateTime` object.
    )
);

System.out.println("created.toString: " + created );
System.out.println("zdt.toString(): " + zdt );

如果created 是今年早些时候,那果然是 2066 年。

created.toString: 2018-01-23T12:34:56-08:00[America/Los_Angeles]

zdt.toString(): 2066-08-09T08:51:38.488980-07:00[America/Los_Angeles]

Millis vs nanos

请注意,java.time 类(例如 InstantZonedDateTime)的分辨率为 nanoseconds。这比使用milliseconds 的旧遗留类java.util.DateCalendar 要好得多。

编写简单的代码

提示:不要在一行代码中编写太多内容。人类难以破译和调试/跟踪。并且 JVM 可能更难优化。通常,在人和机器上编写极其简单的代码行更容易。

所以,让我们把代码分解成简单的几行。

Instant now = Instant.now();  // Current moment in UTC, with a resolution of nanoseconds.
Duration fiveMinutes = Duration.ofMinutes( 5L );  // `Duration` represents a span-of-time unattached to the timeline.
Instant fiveMinutesFromNow = now.plus( fiveMinutes );  // Returns a `Instant`, using our original `Instant` object plus adding some span-of-time.
Clock clock = Clock.fixed( fiveMinutesFromNow , ZoneId.systemDefault() );  // Instantiate a clock frozen at a specific moment about five minutes in the future. This clock does not “tick”, remaining fixed at this one specified moment.

现在将名为 clockClock 对象传递给正在测试的代码。

…
ZonedDateTime zdt = ZonedDateTime.now( clock ) ;  // Tells a lie. Reports a moment about five minutes in the future as “now”. Good for testing.
…

试试看。

now.toString(): 2018-07-17T19:22:48.670320Z

fiveMinutesFromNow.toString(): 2018-07-17T19:27:48.670320Z

zdt.toString(): 2018-07-17T12:27:48.670320-07:00[America/Los_Angeles]

是的,它奏效了。我们将分钟时间视为27 而不是22,即未来五分钟。

在生产环境中传递Clock

要在测试工具之外的生产环境中运行相同的代码,请通过默认的 Clock 实现。

Clock clock =  Clock.systemDefaultZone() ;  // Default `Clock` used implicitly in Java if you do not say otherwise.

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 非常感谢,我试过了,得到了预期的结果,所以在我的情况下,我可以做到Instant now = Instant.now(); Duration duration = Duration.ofMillis( created.toInstant().toEpochMilli() ); Instant instant = now.plus( duration ); Clock clock = Clock.fixed( instant , ZoneId.systemDefault() );我相信
猜你喜欢
  • 2018-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-12
  • 2011-06-06
  • 1970-01-01
  • 2017-05-02
相关资源
最近更新 更多