【问题标题】:How can I create a Java 8 LocalDate from a long Epoch time in Milliseconds?如何从以毫秒为单位的长 Epoch 时间创建 Java 8 LocalDate?
【发布时间】:2016-05-13 00:14:12
【问题描述】:

我有一个外部 API,它将日期返回为 longs,表示为自纪元开始以来的毫秒数。

使用旧式 Java API,我只需使用它构造一个 Date

Date myDate = new Date(startDateLong)

Java 8 的 LocalDate/LocalDateTime 类中的等价物是什么?

我有兴趣将long 表示的时间点转换为我当前本地时区中的LocalDate

【问题讨论】:

  • 嗯,你必须从计算出你关心的时区开始。 “自纪元以来的毫秒数”值为您提供了一个瞬间……它可以指不同时区的不同日期。请记住,java.util.Date 从来都不是像 LocalDate 那样真正的约会——它也是一个瞬间。
  • 查看这个问题:stackoverflow.com/questions/21242110/…,其中涵盖了java.util.DateLocalDate的转换
  • 注意:这个问答对于那些试图将File.lastModified()(epoch millis)转换为LocalDate(Time)的人也很有价值。
  • @GeorgeSiggouroglou 该问题与该问题相反,因此它不是重复的。

标签: java datetime java-8 java-time


【解决方案1】:

如果您有自纪元以来的毫秒数,并希望使用当前本地时区将它们转换为本地日期,您可以使用

LocalDate date =
    Instant.ofEpochMilli(longValue).atZone(ZoneId.systemDefault()).toLocalDate();

但请记住,即使是系统的默认时区也可能会发生变化,因此相同的long 值可能会在后续运行中产生不同的结果,即使在同一台机器上也是如此。

此外,请记住,LocalDatejava.util.Date 不同,它真正代表的是日期,而不是日期和时间。

否则,您可以使用LocalDateTime

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());

【讨论】:

  • +1 来自我以获得更详细的解释。顺便说一句,即使是非系统区域也可以更改(通过 tzupdater-tool 或通过 jdk-change),因此在前后会产生不同的结果。
  • @Meno Hochschild:我没有关注硬编码的时区,而是与用户指定的时区进行比较,从配置文件或环境变量中读取,程序员自然会认为可能会发生变化。硬编码时区确实很像系统默认值;程序员很容易认为他们从未改变过……
  • @Demigod LocalDateTime.ofEpochSecond(…) 需要一个实际的ZoneOffset,但ZoneId.systemDefault() 返回一个ZoneIdZoneId 可以映射到不同的偏移量,具体取决于您所指的时间点。这就是LocalDateTime.ofInstant为你做的事情,根据提供的Instant转换指定的ZoneId
  • Epoch 被定义为 UTC,因此应该与时区无关,因此 ZoneId 应该始终为 UTC。
  • @PlexQ 指定的时区与 Epoch 无关,它确实与时区无关,但与生成的 LocalDateLocalDateTime 的语义有关。你可以指定任何你想要的时区,只要它与这些结果对象的后续使用一致。想想当您处理由不同方法创建的多个对象时会发生什么。 local 日期或日期时间的典型用例包含系统默认时区,例如LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())
【解决方案2】:

你可以从Instant.ofEpochMilli(long)开始:

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();

【讨论】:

  • +1 明确时区。如果省略,JVM 的当前默认时区将隐式应用于确定日期。对于任何给定的时刻,随着东方新的一天黎明的到来,世界各地的日期都会因时区而异。
【解决方案3】:

我想我有一个更好的答案。

new Timestamp(longEpochTime).toLocalDateTime();

【讨论】:

  • 新时间戳(ts).toLocalDateTime().toLocalDate()
  • 我的意思是 - 如果你不介意导入 javal.sql.Timestamp,考虑到 Java 的整体性,我认为这很好,因为它只是 JVM 的所有部分......但感觉有点臭,但我还是更喜欢它,因为它认为纪元基本上是 UTC。
  • Timestamp 类设计不佳且早已过时。您的代码将使用 JVM 的时区设置,但由于此设置可以由您的程序的另一部分或在同一 JVM 中运行的另一个程序更改,我们无法确定它是什么。
  • 明确使用哪个时区总是更好。使用旧的 java.sql.Timestamp 具有隐式应用系统时区的缺点,这通常会导致开发人员混淆。
【解决方案4】:

除了时区和其他东西,new Date(startDateLong) 的一个非常简单的替代方案可能是 LocalDate.ofEpochDay(startDateLong / 86400000L)

【讨论】:

  • 我认为你至少应该解释一下 86400000L 代表什么。
  • 我认为很容易看出它是一天中的毫秒数。
  • 对某些人来说是这样,我认为只有这样才有意义,但如果不重新计算一天真正有多少毫秒,我无法确定。就我个人而言,我不太了解这个数字,以至于我自动知道它代表什么。
  • 还要注意,接受的答案确实是最好的答案,只是看起来势不可挡。在很多情况下,我的简单技巧就足够了。可惜java.time 没有像 Joda 那样包含DateTimeConstants
  • java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
【解决方案5】:

将 now.getTime() 替换为您的 long 值。

//GET UTC time for current date
        Date now= new Date();
        //LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
        LocalDate localDate = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDate();
        DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));

【讨论】:

    【解决方案6】:

    在您的纪元秒时间戳来自 SQL 或以某种方式与 SQL 相关的特定情况下,您可以像这样获取它:

    long startDateLong = <...>
    
    LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();
    

    【讨论】:

    • 这与所提出的问题并没有太大关系
    • @KetanR,我不同意。问题是“如何从epoch-millis 获得LocalDate”,我将展示如何使用java.sql.Date 作为速记。这种方法在已经以某种能力处理 JDBC 的代码中是有意义的,并且工作得很好。如果您仍然不相信,请解释它与最初的问题有何关系。
    • 如果您阅读了这个问题,它会显示“外部 API 将日期返回为 long”,并且您正在解释如果您从 SQL 接收长日期,如何完成此转换。您的回答确实解释了日期转换的一个非常具体的情况,但它与已提出的问题并不真正相关。不过,您的解释可能是对其他一些相关问题的有效答案。
    • @KetanR,如果有人从 SQL 收到长日期,我建议更改他的模式,这样他就不会再收到这种形式的日期。但是,如果一个人从其他地方(外部 API)接收到以毫秒时间戳记的日期,并立即使用这些日期进行 JDBC 查询,那么java.sql.Date 方法是可用的最短的、代码方面的方法之一,我会说它不是当最终结果相同时,所有中间时间对象都可以通过 Instant 进行。
    • 正如我已经说过的并且从您的最新解释中可以看出,您的答案是正确的,但不适用于手头的问题问题说:“我有兴趣将 long 表示的时间点转换为我当前本地时区中的 LocalDate 。”您的回答告诉:“接收日期为毫秒时间戳,并立即使用这些日期进行 JDBC 查询”。我不明白这里有什么不清楚的地方?
    猜你喜欢
    • 2015-12-24
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 2019-02-12
    • 2011-08-02
    • 2017-04-18
    • 2018-01-10
    • 2023-03-30
    相关资源
    最近更新 更多