如何在很长的毫秒时间内创建Java 8 LocalDate?


218

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

使用旧式Java API,我可以简单地Date使用

Date myDate = new Date(startDateLong)

Java 8的LocalDate/ LocalDateTime类中的等效项是什么?

我感兴趣的所代表的时间点转换longLocalDate我目前的本地时区。


6
好吧,您必须首先确定您关心的时区。“自纪元以来的毫秒数”值可为您提供一个即时的时间...可以引用不同时区中的不同日期。请记住,这java.util.Date从来都不是真正的约会LocalDate-也是时间的瞬间。
乔恩·斯基特

2
检查以下问题:stackoverflow.com/questions/21242110/…,其中涵盖了java.util.DateLocalDate
–hotzst

2
注意:此Q&A对尝试将File.lastModified()(epoch millis)转换为的人也很有价值LocalDate(Time)
kevinarpe

Answers:


402

如果您从大纪元起有毫秒数,并且想要使用当前本地时区将其转换为本地日期,则可以使用

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

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

此外,请记住LocalDate,与不同java.util.Date,真正表示的是日期,而不是日期和时间。

否则,您可以使用LocalDateTime

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

2
向我+1以获得更详细的解释。顺便说一句,即使非系统区域也可以更改(通过tzupdater-tool或jdk-change),因此在此之前和之后都会产生不同的结果。
Meno Hochschild

2
@Meno Hochschild:我不是在关注硬编码的时区,而是将其与用户指定的时区进行比较,从配置文件或环境变量中读取,程序员自然而然地认为可能会改变。硬编码时区的确与系统默认值非常相似。程序员很容易以为他们永远都不会改变……
Holger

2
@Demigod LocalDateTime.ofEpochSecond(…)需要实际值ZoneOffset,但 ZoneId.systemDefault()返回ZoneId。A ZoneId可以映射到不同的偏移量,具体取决于您指的时间点。这就是LocalDateTime.ofInstant您要做的,ZoneId根据提供的转换指定的内容Instant
Holger

2
纪元定义为UTC,因此应与时区无关,因此ZoneId应始终为UTC。
PlexQ

2
@PlexQ指定的时区与纪元无关,纪元确实与时区无关,但与结果LocalDateor 的语义有关LocalDateTime。您可以指定所需的任何时区,只要它与这些结果对象的后续使用一致即可。想想当您处理由不同方法创建的多个对象时会发生什么。当地日期或日期时间的典型用例包含系统默认时区,例如LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())
Holger


12

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

new Timestamp(longEpochTime).toLocalDateTime();

new Timestamp(ts).toLocalDateTime()。toLocalDate()
Stepan

5
我的意思是-如果您不介意导入javal.sql.Timestamp,考虑到Java的整体性质,我认为这很好,因为它只是JVM的全部...但是感觉有点臭,但我仍然喜欢它,它认识到时代基本上是UTC。
PlexQ

1
Timestamp课程的设计不佳,而且已经过时了。您的代码将使用JVM的时区设置,但是由于您的程序的另一部分或运行在同一JVM中的另一个程序可以更改此设置,因此我们无法确定它是什么。
Ole VV

1
最好明确使用哪个时区。使用旧的java.sql.Timestamp的缺点是隐式应用了系统时区,这通常在开发人员之间引起混乱。
罗斯兰

3

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


6
我认为您至少应该解释86400000L的含义。
BAERUS '17

3
我认为很容易发现这就是一天中的毫秒数。
Michael Piefel

7
对于某些情况,我认为只有这样才有意义,但是如果不重新计算一天实际有多少毫秒,我就不确定。只是为自己说话,我不太了解这个数字,以至于我自动知道它代表什么。
BAERUS

还要注意,公认的答案确实是最好的答案,看起来似乎是压倒性的。在许多情况下,我的简单技巧就足够了。可惜java.time没有DateTimeConstants乔达那样。
Michael Piefel

2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim

1

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

//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();

2
这并没有真正涉及多以问的问题
科坦[R

@ KetanR,我不同意。现在的问题是“如何获得一个LocalDateepoch-millis”,我展示了如何使用java.sql.Date速记。这种方法在已经以某种能力处理JDBC的代码中很有意义,并且工作得很好。如果您仍然不确定,请说明它与最初的问题无关。
M. Prokhorov

2
如果您读了这个问题,它会说“返回给我长久的日期的外部API”,并且您正在解释如果您从SQL接收长时的日期,则如何完成此转换。您的答案确实解释了日期转换的一个非常具体的情况,但与提出的问题并不真正相关。您的解释可能是对其他一些相关问题的有效答案。
Ketan R

@KetanR,如果有人从SQL接收长日期,我建议更改他的架构,这样他就不再以这种形式接收日期。但是,如果从其他地方(外部API)接收日期作为毫秒时间戳,并立即使用这些日期进行JDBC查询,则java.sql.Date方法在代码方面是最短的可用方法之一,我会说这不是那么有用虽则去Instant了所有的中间时间对象时,最终的结果是一样的。
M. Prokhorov

2
正如我已经说过的,从您的最新解释中可以明显看出,您的答案是正确的,但并非针对当前的问题。问题说:“我有兴趣将长整数表示的时间点转换为当前本地时区中的LocalDate。您的答案告诉您:“将日期接收为millis-timestamps,并立即使用这些日期进行JDBC查询”。我不明白这里不清楚什么?
Ketan R
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.