如何在Java 8中从LocalDateTime获取毫秒


284

我想知道如果有一种方法,因为1970年1月1日(时期),以获得当前毫秒使用新的LocalDate,LocalTime或LocalDateTimeJava的8类。

已知的方法如下:

long currentMilliseconds = new Date().getTime();

要么

long currentMilliseconds = System.currentTimeMillis();

6
这有什么错System.currentTimeMillis()?
— 达伍德·伊本·卡里姆

16
@DavidWallace他正在尝试获取日期时间,而不是当前时间?
— Anubian Noob 2014年

2
“ ...获得当前毫秒数的方法...”
— 达伍德·伊本·卡里姆

从1970年1月1日开始的毫秒数。我在徘徊是否有一种方法可以使用Java 8 LocalDate,LocalTime和LocalDateTime的新类来获取它们,因为我没有找到一个。
— 乔治·西格古罗格

1
我对这些课程的目的的理解是,它是对时间的“以人为本”的理解,currentTimeMillis在这种情况下将是无关紧要的。日历+壁钟的精度非常好,无需担心时区和本地性。因此,无法从本地时间返回“ UTC时间”
— Gus

Answers:


324

我不能完全确定“当前毫秒”的含义,但我认为这是自“纪元”(即UTC 1970年1月1日午夜)以来的毫秒数。

如果你想找到,因为时代的毫秒数眼下,然后用System.currentTimeMillis()作为Anubian菜鸟指出。如果是这样,则没有理由使用任何新的java.time API来执行此操作。

但是,也许您已经LocalDateTime从某个位置获取了一个或类似的对象,并且想要将其转换为自纪元以来的毫秒数。无法直接执行此操作,因为LocalDateTime对象族不知道它们位于哪个时区。因此,需要提供时区信息以找到相对于纪元的时间(UTC)。

假设您有一个LocalDateTime像这样的人:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

您需要应用时区信息,并给ZonedDateTime。我和洛杉矶在同一时区,所以我会做这样的事情:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

当然,这是关于时区的假设。并且,在某些情况下可能会发生,例如,如果当地时间恰好是在夏令时(夏季时间)过渡附近命名的时间。让我们搁置这些,但是您应该意识到这些情况的存在。

无论如何,如果您可以获取有效的ZonedDateTime,则可以将其转换为自纪元以来的毫秒数,如下所示:

long millis = zdt.toInstant().toEpochMilli();

5
请注意,ZonedDateTime已经具有该getEpochSecond方法(通过ChronoZonedDateTime default)。不需要Instant。
— 2014年

12
当然,如果您需要的只是秒,而不是毫秒。
— 斯图尔特·马克斯

17
通过使用zdt.get(ChronoField.MILLI_OF_SECOND)避免对nanos进行数学运算。使用zdt.toInstant()。toEpochMilli()避免所有数学运算
— JodaStephen 2014年

2
请注意,这zdt.toInstant().toEpochMilli();将为您提供相应UTC值的毫秒数,而不是您的分区日期时间的毫秒数。我发现这很困难。toInstant()给您一个UTC时间。如果您想要以毫秒为单位的当地时间,这将无法满足您的期望。因此,例如,如果您使用的是+02:00分区时间,则返回的时间将比预期的少3600 * 2 * 1000毫秒。
— Per Lundberg

2
@PerLundberg我只是相比ZonedDateTime.now().toInstant().toEpochMilli(),LocalDateTime.now().toInstant(OffsetDateTime.now().getOffset()).toEpochMilli(),LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(),Calendar.getInstance().getTime().getTime(),new Date().getTime()和System.currentTimeMillis()。似乎唯一的“关闭”方法是您建议的方法:LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()给您当地日期的毫秒数,就好像它是UTC日期一样;即,如果本地日期是UTC + 2,则您的方法会在未来2小时内提供毫秒数。
— walen

81

我要做的是不指定时区,

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

给

ldt 1424812121078 
ctm 1424812121281

如您所见,除了执行时间短之外,数字是相同的。

以防万一您不喜欢System.currentTimeMillis,请使用 Instant.now().toEpochMilli()


3
不,Epoch与UTC有关,但是您可以从本地区域获取当前时间。
— 拉斐尔·拉姆布雷夫斯

2
@ChristofferHammarström自该纪元以来经过的毫秒数是事实,与时区无关。不论您在一天中的什么时间都以毫秒为单位。这两个结果是不同的,因为brian的机器花了203毫秒来执行第二个命令。
— 抓取

用户在其他时区时可以使用UTC
— 吗

2
@GilbertS,您可能永远不要使用这个确切的代码,请按预期使用API​​。当存储在计算机上或传输给其他用户时,日期时间应始终为UTC。通常应使用他们自己的时区设置将其作为本地日期时间呈现给用户。
— 布赖恩

20

要避免ZoneId,可以执行以下操作:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

获得0作为值,没错!


8
ZoneOffset.ofTotalSeconds(0)它与ZoneOffset.UTC
— Anton Novopashin

1
是的,这是我反对@AntonNovopashin的评论。由于您需要UTC,所以很好(您可能想在答案中提到它)。BTW ZoneOffset是的子类ZoneId,所以我不会确切地说您避免了它,但是只要您感到高兴……
— Ole VV

我的第一条评论有些刺耳,但并不意味着冒犯他人。你冒犯了 对不起。我已经删除了。请允许我反过来问:我们想避免的原因是ZoneId什么?
— Ole VV

@ OleV.V是否可以使用UTC。不仅适用于居住在UTC时区的人们。
— GilbertS

1
@GilbertS我认为没有人住在UTC时区。建议将UTC用于跨时区的时间,这是一种好的做法。参见例如Java最佳实践,适用于不同地理位置的用户进行日期处理/存储。也许我不明白您的问题?
— Ole VV

15

从Java 8开始,您可以调用java.time.Instant.toEpochMilli()。

例如通话

final long currentTimeJava8 = Instant.now().toEpochMilli();

给您与以下相同的结果

final long currentTimeJava1 = System.currentTimeMillis();

1
“为您提供与...相同的结果”……但需要更多的CPU能力,并给垃圾收集器带来更多压力。
— VasiliNovikov '18

我希望看到以上内容量化(特别是对于正常使用-例如,对于某些对性能至关重要的实时应用程序而言不是...)
— Brian Agnew

11

您还可以使用java.sql.Timestamp来获取毫秒数。

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);

您忽略了对时区的紧迫需求。我不建议这样做。同样,Timestamp该类早已过时并且充满了设计问题,因此我宁愿避免使用它,尤其是当我们可以使用java.timelike中的类时LocalDateTime。
— Ole VV

@ OleV.V。只是对的设计问题感到好奇Timestamp,您可以分享一些有关此的文章吗?它也帮助我避免使用Timestamp代码。谢谢!
— Nalam

1
简而言之,它实现为的子类,Date但通常不能作为子类处理Date。Date不赞成继承自和构造函数的大多数方法。它的toString方法使用JVM的时区,这使许多人感到困惑,因为Timestamp在不同的计算机上JVM的时区打印方式不同(例如)。
— Ole VV

这非常适合单元测试。只需将现在替换为LocalDate.of(year, month, day)
— G_V

这是解决“始终为UTC”值的公认答案。
— LeYAUable


3

如果您有Java 8 Clock,则可以使用clock.millis()(尽管它建议您使用clock.instant()Java 8 Instant,因为它更准确)。

为什么要使用Java 8时钟?因此,在您的DI框架中,您可以创建一个Clock Bean:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

然后在测试中,您可以轻松模拟它:

@MockBean private Clock clock;

或者您可以使用其他bean:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

这有助于确定日期和时间无法估量的测试。


1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}

0

为什么没有人提到该方法LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

这似乎比上面的许多建议答案还短...


这就是我想要的。那个公认的答案给了我勇气。
— Brill Pappin

接受API 26中唯一可用的方法:{
— Brill Pappin

1
因为只给几秒钟。toEpochMilli考虑到您甚至可以在LocalDateTime中指定十亿分之一秒的事实,所以没有方法是很奇怪的:有一个方法LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)。
— izogfif
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.