如何以毫秒为单位返回LocalDate.now()?

use*_*472 13 timestamp java-8 java-time localdate

我现在创建日期:

ZoneId gmt = ZoneId.of("GMT");
LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDateNow = localDateTime.toLocalDate();
Run Code Online (Sandbox Code Playgroud)

然后我希望以毫秒为单位返回此日期:

localDateNow.atStartOfDay(gmt) - 22.08.2017
localDateNow.atStartOfDay(gmt).toEpochSecond(); - 1503360000 (18.01.70)
Run Code Online (Sandbox Code Playgroud)

我怎么能LocalDate.now()在几毫秒内返回?

小智 18

调用toInstant().toEpochMilli(),所建议@JB Nizet的评论,是正确的答案,但有关于使用当地的日期,你必须知道一点,棘手的细节.

但在此之前,还有其他一些小细节:

  • 而不是ZoneId.of("GMT")你可以使用内置常量ZoneOffset.UTC.它们是等价的,但是如果API已经提供了完全相同的东西,则不需要创建额外的冗余对象.
  • 而不是打电话LocalDateTime.now()然后.toLocalDate(),你可以LocalDate.now()直接打电话- 他们是等同的.

现在是棘手的细节:当您调用now()方法(用于LocalDateTime或者LocalDate)时,它使用JVM的默认时区来获取当前日期的值,并且此值可能会有所不同,具体取决于JVM中配置的时区.

在我正在使用的JVM中,默认时区是America/Sao_Paulo,这里的当地时间是09:37 AM.所以LocalDate.now()回报2017-08-22(八月22 2017).

但是如果我将默认时区更改为Pacific/Kiritimati,则返回2017-08-23.这是因为在基里蒂马蒂,现在已经是年8月23 2017年(和本地时间里面,在我写这篇文章的那一刻,是上午02点37分).

因此,如果我在默认时区为Pacific/Kiritimati以下时运行此代码:

LocalDate dtNow = LocalDate.now(); // 2017-08-23
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());
Run Code Online (Sandbox Code Playgroud)

输出是:

1503446400000

这相当于2017年8月23 UTC的午夜.

如果我在默认时区运行相同的代码America/Sao_Paulo,结果将是:

15033.6亿

这相当于2017年8月22 UTC的午夜.

使用now()使您的代码取决于JVM的默认时区.即使在运行时,也可以在不事先通知的情况下更改此配置,从而在发生此类更改时使代码返回不同的结果.

而且你不需要这么极端的情况(就像有人把JVM误配置到"非常远"的时区).在我的情况下,例如,在America/Sao_Paulo时区,如果我在晚上11点运行代码,LocalDate将返回8月22 ,但UTC中的当前日期将已经是8月23 .那是因为圣保罗的晚上11点与UTC 的第二天凌晨 2点相同:

// August 22th 2017, at 11 PM in Sao Paulo
ZonedDateTime z = ZonedDateTime.of(2017, 8, 22, 23, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2017-08-22T23:00-03:00[America/Sao_Paulo]
System.out.println(z.toInstant()); // 2017-08-23T02:00:00Z (in UTC is already August 23th)
Run Code Online (Sandbox Code Playgroud)

所以使用a LocalDate.now()不能保证我将始终拥有UTC当前日期.


如果您想要UTC中当前日期(无论JVM默认时区如何)并将时间设置为午夜,最好使用ZonedDateTime:

// current date in UTC, no matter what the JVM default timezone is 
ZonedDateTime zdtNow = ZonedDateTime.now(ZoneOffset.UTC);
// set time to midnight and get the epochMilli
System.out.println(zdtNow.with(LocalTime.MIDNIGHT).toInstant().toEpochMilli());
Run Code Online (Sandbox Code Playgroud)

输出是:

15033.6亿

这相当于2017年8月22 UTC的午夜.

另一种方法是将时区传递给LocalDate.now,因此它可以获得指定区域上当前日期的正确值:

// current date in UTC, no matter what the JVM default timezone is 
LocalDate dtNowUtc = LocalDate.now(ZoneOffset.UTC);
// set time to midnight and get the epochMilli
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());
Run Code Online (Sandbox Code Playgroud)