How to get milliseconds from LocalDateTime in Java 8
我想知道是否有一种方法可以使用Java 8的新LocalDate,LocalTime或LocalDateTime类获得自1-1-1970(epoch)以来的当前毫秒数。
已知的方法如下:
1
| long currentMilliseconds = new Date(). getTime(); |
要么
1
| long currentMilliseconds = System. currentTimeMillis(); |
-
System.currentTimeMillis()有什么问题?
-
@DavidWallace他试图获得约会的时间,而不是现在的时间?
-
"......获得当前毫秒的方法......"
-
毫秒计数从1-1-1970。 如果有一种方法可以让他们使用Java 8 LocalDate,LocalTime和LocalDateTime的新类,我会徘徊,因为我没找到。
-
我对这些课程目的的理解是,它是一种"以人为本"的时间理解,currentTimeMillis在这种背景下是无关紧要的。 认为日历+挂钟具有非常好的精确度,并且不关心时区和地点。 所以没有办法从LocalTime回到"UTC时间"
我不完全确定你的"当前毫秒"是什么意思,但我认为它是自"世纪"以来的毫秒数,即1970年1月1日午夜。
如果你想现在找到自纪元以来的毫秒数,那么就像Anubian Noob指出的那样使用System.currentTimeMillis()。如果是这样,没有理由使用任何新的java.time API来执行此操作。
但是,也许您已经从某个地方获得了LocalDateTime或类似的对象,并且您希望将其转换为自纪元以来的毫秒数。直接执行此操作是不可能的,因为LocalDateTime对象系列没有关于它们所处的时区的概念。因此需要提供时区信息以查找相对于以UTC为单位的时期的时间。
假设你有一个像这样的LocalDateTime:
1
| LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16); |
您需要应用时区信息,并提供ZonedDateTime。我和洛杉矶在同一时区,所以我会这样做:
1
| ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles")); |
当然,这会对时区做出假设。并且存在可能发生的边缘情况,例如,如果本地时间恰好命名接近夏令时(夏令时)转换的时间。让我们把这些放在一边,但你应该知道存在这些情况。
无论如何,如果你能得到一个有效的ZonedDateTime,你可以将它转换为自纪元以来的毫秒数,如下所示:
1
| long millis = zdt.toInstant().toEpochMilli(); |
-
请注意,ZonedDateTime已经具有getEpochSecond方法(通过ChronoZonedDateTime默认值)。不需要Instant。
-
当然,如果您需要的只是秒,而不是毫秒。
-
好吧,我不精确:ZonedDateTime也有Instant s getNano方法,所以你不能在你的例子中用zdt替换inst吗?
-
哎呀。 ChronoZonedDateTime toEpochSecond不getEpochSecond。所以是的,我认为这允许跳过Instant的使用。我会测试和更新。
-
@mabi更新。感谢您指出这种简化。
-
使用zdt.get(ChronoField.MILLI_OF_SECOND)避免使用nanos数学。使用zdt.toInstant()。toEpochMilli()避免所有数学运算
-
@JodaStephen zdt.getLong而不仅仅是get(返回int)
-
请注意,zdt.toInstant().toEpochMilli();将为您提供相应UTC值的毫秒数,而不是您的分区日期时间。我发现这很难。 toInstant()为您提供UTC即时。如果你想要毫克当地时间,这将无法满足你的期望。所以,如果你是使用+02:00分区时间,您的返回时间将比您预期的少3600 * 2 * 1000毫秒。
-
如果您出于任何原因(可能是因为与现有的非UTC操作应用程序代码交互)想要本地时间,LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()就是您想要的。
-
@PerLundberg你确定吗? Javadoc说toInstant()"返回一个Instant,表示时间线上与该日期时间相同的点。计算结合了本地日期时间和偏移量。"因此,似乎确实考虑了时区。然后你说要获得当地时间毫秒,你必须将它转换为UTC时刻,不会返回UTC时间而不是本地时间吗?
-
@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是的。听起来很荒谬,有时你可能想要包含UTC偏移的本地时间毫秒。从技术上讲,这是错误的,因为millis时间戳应该是UTC,但......
-
@PerLundberg但你说:"请注意,zdt.toInstant().toEpochMilli()将为您提供相应UTC值的毫秒数,而不是您的分区日期时间[...] toInstant()为您提供UTC时刻。如果您想要当地时间毫无疑问,这不会给你你所期望的。"这是不正确的。 toInstant()精确地为您提供本地时刻,而不是UTC时刻。换句话说,它返回与Date相同的millis值,与Calendar相同,与System相同......这正是大多数人所期望的。
-
@PerLundberg当然,您的代码给出了您所说的内容:当地时间值的毫秒数就像是UTC时间一样。但这不是答案所要求的,也不是大多数人想要得到的,而你的评论可能会误导很多用户获得错误的毫秒价值。
-
@walen Fair点,我知道这是一个有点边缘的情况。这是一个相关(但不完全相同)的问题。我并不是说大多数人都希望得到这个,但在我写答案的时候我需要它。 :-)所以:我的评论给出了从纪元开始的毫秒数,包括时区偏移量,这通常不是你想要的,但对于你想要它的那些边缘情况=>使用它。否则,请勿使用此方法。
我这样做我没有指定时区是,
1 2
| System. out. println("ldt" + LocalDateTime. now(). atZone(ZoneId. systemDefault()). toInstant(). toEpochMilli());
System. out. println("ctm" + System. currentTimeMillis()); |
给
1 2
| ldt 1424812121078
ctm 1424812121281 |
如果您不喜欢System.current ....,请使用Instant.now().toEpochMilli()
-
System.currentTimeMillis()是相对于UTC的,因此您应该使用ZoneOffset.UTC而不是ZoneId.systemDefault()。
-
不,Epoch与UTC相关,但您可以从当地区域获取当前时间。
要避免使用ZoneId,您可以:
1 2 3
| LocalDateTime date = LocalDateTime. of(1970, 1, 1, 0, 0);
System. out. println("Initial Epoch (TimeInMillis):" + date. toInstant(ZoneOffset. ofTotalSeconds(0)). toEpochMilli()); |
获得0作为价值,这是正确的!
-
ZoneOffset.ofTotalSeconds(0)与ZoneOffset.UTC相同
-
是的,这是我支持@Antonnovopashin的评论。由于你需要UTC,你很好(你可能想在答案中提到)。 BTW ZoneOffset是ZoneId的子类,所以我不会说你已经避免了它,但只要你开心......
-
我的第一个评论有点苛刻,但并不意味着冒犯。你冒犯了对不起。我删除了它。请允许我反过来问:我们想要避免ZoneId的原因是什么?
从Java 8开始,您可以调用java.time.Instant.toEpochMilli()。
例如电话
1
| final long currentTimeJava8 = Instant.now().toEpochMilli(); |
给你相同的结果
1
| final long currentTimeJava1 = System. currentTimeMillis(); |
-
"给你的结果与"相同......但是需要更多的CPU能力并且更多地强调垃圾收集器。
你也可以使用java.sql.Timestamp来获得毫秒。
1 2 3
| LocalDateTime now = LocalDateTime. now();
long milliSeconds = Timestamp. valueOf(now ). getTime();
System. out. println("MilliSeconds:"+milliSeconds ); |
谢谢!
-
你忽略了对时区的迫切需要。我不建议这样做。此外,Timestamp类已经过时并且充满了设计问题,因此我宁愿避免它,特别是当我们可以使用java.time中的类,如LocalDateTime时。
-
@ OleV.V。只是好奇Timestamp的设计问题,你能分享一些文章吗?它帮助我避免使用我的代码中的Timestamp。谢谢!
-
简而言之,它是作为Date的子类实现的,但通常不能作为Date处理。不推荐使用从Date继承的大多数方法和一个构造函数。它的toString方法使用JVM的时区,由于在不同的计算机上以不同的方式打印相同的Timestamp,因此会混淆很多(例如)。
-
这非常适合单元测试。只需用LocalDate.of(year, month, day)替换now即可
要以毫秒(从纪元开始)获取当前时间,请使用System.currentTimeMillis()。
如果您有Java 8 Clock,那么您可以使用clock.millis()(尽管它建议您使用clock.instant()来获取Java 8 Instant,因为它更准确)。
你为什么要使用Java 8时钟?所以在您的DI框架中,您可以创建一个Clock bean:
1 2 3 4
| @Bean
public Clock getClock() {
return Clock.systemUTC();
} |
然后在你的测试中你可以轻松模拟它:
1
| @MockBean private Clock clock; |
或者你可以拥有一个不同的bean:
1 2 3 4
| @Bean
public Clock getClock() {
return Clock.fixed(instant, zone);
} |
这有助于测试断言日期和时间无法估量。