Java8 中的 LocalDateTime 默认格式化字符串中为啥会有个T
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8 中的 LocalDateTime 默认格式化字符串中为啥会有个T相关的知识,希望对你有一定的参考价值。
下面是LocalDateTime 的toString方法,可以看到遵循的是国际标准ISO 8601。
国际标准ISO 8601规定
日期和时间的组合表示时:要在时间前面加一大写字母T,如要表示北京时间2004年5月3日下午5点30分8秒,可以写成2004-05-03T17:30:08+08:00或20040503T173008+08。
/*** Outputs this date-time as a @code String, such as @code 2007-12-03T10:15:30.
* <p>
* The output will be one of the following ISO-8601 formats:
* <ul>
* <li>@code uuuu-MM-dd'T'HH:mm</li>
* <li>@code uuuu-MM-dd'T'HH:mm:ss</li>
* <li>@code uuuu-MM-dd'T'HH:mm:ss.SSS</li>
* <li>@code uuuu-MM-dd'T'HH:mm:ss.SSSSSS</li>
* <li>@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS</li>
* </ul>
* The format used will be the shortest that outputs the full value of
* the time where the omitted parts are implied to be zero.
*
* @return a string representation of this date-time, not null
*/
@Override
public String toString()
return date.toString() + 'T' + time.toString();
参考技术A 既然说默认格式,那要看系统的时区等信息
~~~~~~
~~
~
~~~~~~~~~~
如何从 Java 8 中的 LocalDateTime 获取毫秒数
【中文标题】如何从 Java 8 中的 LocalDateTime 获取毫秒数【英文标题】:How to get milliseconds from LocalDateTime in Java 8 【发布时间】:2014-07-19 14:38:15 【问题描述】:我想知道是否有办法使用 Java 8 的新 LocalDate
、LocalTime
或 LocalDateTime
类获取自 1970 年 1 月 1 日(纪元)以来的当前毫秒数。
已知方法如下:
long currentMilliseconds = new Date().getTime();
或
long currentMilliseconds = System.currentTimeMillis();
【问题讨论】:
System.currentTimeMillis()
有什么问题?
@DavidWallace 他试图获取日期的时间,而不是当前时间?
"...获取当前毫秒数的方法..."
从 1970 年 1 月 1 日开始计算的毫秒数。如果有一种方法可以使用 Java 8 LocalDate、LocalTime 和 LocalDateTime 的新类来获取它们,我正在徘徊,因为我没有找到。
我对这些课程的目的的理解是,它是对时间的“以人为本”的理解,currentTimeMillis
在这种情况下是无关紧要的。想想日历+挂钟,精度非常好,不用担心时区和地点。所以没有办法从 LocalTime 回到“UTC 时间”
【参考方案1】:
我认为这更简单:
ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());
Assert.assertEquals(System.currentTimeMillis(), zdt.toInstant().toEpochMilli());
获取类似于 System.currentTimeMillis() 的毫秒(来自 UTC)。
【讨论】:
【参考方案2】:对于 LocalDateTime,我这样做:
LocalDateTime.of(2021,3,18,7,17,24,341000000)
.toInstant(OffsetDateTime.now().getOffset())
.toEpochMilli()
【讨论】:
【参考方案3】:日期和时间字符串转长(毫秒):
String dateTimeString = "2020-12-12T14:34:18.000Z";
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDateTime localDateTime = LocalDateTime
.parse(dateTimeString, formatter);
Long dateTimeMillis = localDateTime
.atZone(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
【讨论】:
【参考方案4】:你可以试试这个:
long diff = LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
【讨论】:
请添加一些解释。【参考方案5】:我没有指定时区的做法是,
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()
【讨论】:
不,Epoch 与 UTC 相关,但您从本地区域获取当前时间。 @ChristofferHammarström 自纪元以来经过的毫秒数是与时区无关的事实。无论您在一天中的什么时间调用它,它都是相同的毫秒数。这两个结果是不同的,因为 brian 的机器执行第二个命令花了 203 毫秒。 当用户可能在不同的时区时是否可以使用 UTC @GilbertS 你可能永远不应该使用这个确切的代码,按预期使用 API。当存储在计算机上或传输给其他用户时,日期时间应始终为 UTC。通常应该使用他们自己的时区设置将其作为本地日期时间呈现给用户。 正如@Fletch 已经提到的,结果与时区无关。差异背后的原因是执行第二个命令需要 203 毫秒。您可以将System.out.println("ctm " + System.currentTimeMillis());
替换为System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
,即执行完全相同的语句两次,您仍然会看到与否相同的差异。自上次执行同一条语句以来经过的毫秒数。【参考方案6】:
为什么没有人提到LocalDateTime.toEpochSecond()
的方法:
LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);
这似乎比上面许多建议的答案要短...
【讨论】:
这就是我要找的。那个公认的答案让我大吃一惊。 接受它仅在 API 26 中可用: 因为它只给出几秒钟。奇怪的是没有toEpochMilli
方法,考虑到您可以在 LocalDateTime 中指定甚至纳秒的事实:有一个方法 LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
。【参考方案7】:
您也可以使用java.sql.Timestamp
来获取毫秒数。
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
在不同的计算机上打印的方式不同(example)。
这非常适合单元测试。只需将 now 替换为 LocalDate.of(year, month, day)
这应该是解决“始终 UTC”值的公认答案。【参考方案8】:
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();
【讨论】:
【参考方案9】:从 Java 8 开始,您可以调用 java.time.Instant.toEpochMilli()
。
例如通话
final long currentTimeJava8 = Instant.now().toEpochMilli();
为您提供与
相同的结果final long currentTimeJava1 = System.currentTimeMillis();
【讨论】:
“给你同样的结果”...但是需要更多的 CPU 资源并且给垃圾收集器带来更多的压力。 我希望看到上述量化(尤其是对于正常使用 - 例如,不适用于某些性能关键的实时应用程序......)【参考方案10】:如果您有 Java 8 时钟,那么您可以使用 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);
这有助于对日期和时间进行不可估量的测试。
【讨论】:
【参考方案11】:要避免 ZoneId,您可以这样做:
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,所以没问题(您可能想在答案中提及)。顺便说一句,ZoneOffset
是ZoneId
的子类,所以我不能完全说你已经避免了它,但只要你开心……
我的第一条评论有点苛刻,但并不意味着冒犯。你冒犯了。我很抱歉。我已将其删除。请允许我反过来问:我们想要避免 ZoneId
的原因可能是什么?
@OleV.V 可以使用 UTC。不仅适用于生活在 UTC 时区的人。
@GilbertS 我认为没有人生活在 UTC 时区。建议对跨时区使用的时间使用 UTC 作为一种良好做法。参见例如Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users。或者我没听懂你的问题?【参考方案12】:
要获取当前时间(以毫秒为单位)(从纪元开始),请使用System.currentTimeMillis()
。
【讨论】:
【参考方案13】:我不完全确定您所说的“当前毫秒”是什么意思,但我假设它是自“纪元”即 UTC 1970 年 1 月 1 日午夜以来的毫秒数。
如果您想查找自当前纪元以来的毫秒数,然后将System.currentTimeMillis()
用作Anubian Noob has pointed out。如果是这样,就没有理由使用任何新的 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();
【讨论】:
请注意,ZonedDateTime 已经拥有getEpochSecond
方法(通过ChronoZonedDateTime default)。不需要Instant
。
当然,如果您只需要几秒,而不是毫秒。
嗯,我说的不准确:ZonedDateTime
也有 Instant
s getNano
方法,所以在你的例子中你不能用 zdt
替换 inst
吗?
使用 zdt.get(ChronoField.MILLI_OF_SECOND) 避免 nanos 上的数学运算。使用 zdt.toInstant().toEpochMilli() 避免所有数学运算
不管怎样,既然你和@walen都发表了评论,我决定现在删除我原来的消息,以免误导人。以上是关于Java8 中的 LocalDateTime 默认格式化字符串中为啥会有个T的主要内容,如果未能解决你的问题,请参考以下文章