正如@JB Nizet 的评论toInstant().toEpochMilli()
所建议的那样,调用是正确的答案,但是您必须注意有关使用本地日期的一些小而棘手的细节。
但在此之前,还有一些其他的小细节:
- 而不是
ZoneId.of("GMT")
你可以使用内置的常量ZoneOffset.UTC
。它们是等价的,但如果 API 已经提供了完全相同的对象,则无需创建额外的冗余对象。
- 您可以直接调用而不是调用
LocalDateTime.now()
then ——它们是等价的。.toLocalDate()
LocalDate.now()
现在是棘手的细节:当您调用该now()
方法(对于LocalDateTime
or LocalDate
)时,它使用 JVM 的默认时区来获取当前日期的值,并且该值可能会根据 JVM 中配置的时区而有所不同。
在我使用的 JVM 中,默认时区是America/Sao_Paulo
,这里的本地时间是09:37 AM。所以LocalDate.now()
返回2017-08-22
(2017 年 8 月22日)。
但是,如果我将默认时区更改为Pacific/Kiritimati
,它会返回2017-08-23
。那是因为在 Kiritimati,现在已经是 2017 年 8 月23日(而在我写这篇文章的那一刻,那里的当地时间是02:37 AM)。
因此,如果我在默认时区为时运行此代码Pacific/Kiritimati
:
LocalDate dtNow = LocalDate.now(); // 2017-08-23
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());
输出是:
1503446400000
这相当于 2017 年 8 月23日UTC 午夜。
如果我在默认时区为 时运行相同的代码America/Sao_Paulo
,结果将是:
1503360000000
这相当于 2017 年 8 月22日UTC 午夜。
Usingnow()
使您的代码依赖于 JVM 的默认时区。并且即使在运行时也可以在不通知的情况下更改此配置,从而使您的代码在发生此类更改时返回不同的结果。
而且您不需要这样的极端情况(例如有人将 JVM 错误配置为“非常远”的时区)。例如,在我的情况下,在America/Sao_Paulo
时区中,如果我在11 PM运行代码,LocalDate
将返回 August 22 th,但 UTC 的当前日期已经是 August 23 th。这是因为圣保罗的晚上 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)
因此,使用 aLocalDate.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());
输出是:
1503360000000
这相当于 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());