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


284

我想知道如果有一种方法,因为1970年1月1日(时期),以获得当前毫秒使用新的LocalDateLocalTimeLocalDateTimeJava的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但通常不能作为子类处理DateDate不赞成继承自和构造函数的大多数方法。它的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.