android 将LocalDateTime转换为Instant给予不同的值

q43xntqr  于 2023-01-24  发布在  Android
关注(0)|答案(2)|浏览(141)

我尝试使用LocalDateTime在应用程序中操作日期,但我注意到从中获取纪元秒数返回的值与我预期的值不同

val now1 = Instant.now().epochSecond - 60
val now2 = Instant.now().minusSeconds(60).epochSecond
val now3 = LocalDateTime.now().minusSeconds(60).toEpochSecond(ZoneOffset.UTC)
val now4 = System.currentTimeMillis() / 1000 - 60

产出

Now1 = 1674501451
Now2 = 1674501451
Now3 = 1674512251
Now4 = 1674501451

注意Now3的值是不同的,这是怎么回事?

rdlzhqv9

rdlzhqv91#

您需要将LocalTime#now(ZoneId zone)ZoneOffset.UTC一起使用,以获取UTC的本地时间;否则,系统提取系统所在时区的本地时间。

    • 演示**:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

class Main {
    public static void main(String[] args) {
        Instant now = Instant.now();
        var now1 = TimeUnit.SECONDS.convert(now.toEpochMilli(), TimeUnit.MILLISECONDS) - 60;
        var now2 = TimeUnit.SECONDS.convert(now.minusSeconds(60).toEpochMilli(), TimeUnit.MILLISECONDS);
        var now3 = LocalDateTime.now(ZoneOffset.UTC).minusSeconds(60).toEpochSecond(ZoneOffset.UTC);
        var now4 = System.currentTimeMillis() / 1000 - 60;
        System.out.println(now1);
        System.out.println(now2);
        System.out.println(now3);
        System.out.println(now4);
    }
}
    • 示例运行的输出**:
1674506413
1674506413
1674506413
1674506413

ONLINE DEMO
从**Trail: Date Time**了解有关现代日期-时间API的更多信息。

rqcrx0a6

rqcrx0a62#

TL;医生

  • JVM当前的默认时区比UTC早三个小时,这就是您的结果。
  • 👉您对LocalDateTime类的使用不当。

∮时刻对不时刻∮
我正在尝试使用LocalDateTime操作日期
别说了
如果你正在表示一个时刻,时间线上的一个特定点,不要使用LocalDateTime。这个类保存了一个日期和一天中的时间,但是缺少时区或UTC偏移量的上下文。要表示一个时刻,使用:👉 do not use LocalDateTime . That class holds a date with a time-of-day but lacks the context of a time zone or offset-from-UTC. To represent a moment use:

我无法想象调用LocalDateTime.now是正确的事情的任何场景。

LocalDateTime#toEpochSecond

LocalDateTime上调用toEpochSecond方法在概念上是比较棘手的,作为一个概念,LocalDateTime没有epoch reference点,只是一个带时间的日期,比如"2023年1月23日中午"本身就没有具体的含义,不能被固定在时间线上的某个点上。所以将"2023年1月23日中午"与一个参考点进行比较是没有意义的,比如UTC中看到的1970年的第一时刻,1970年1月1日零时
实际上,LocalDateTime类的实现就像是在UTC中一样。因此,在内部,该类计算自1970 - 01 - 01T00:00Z以来的整数秒数,加上小数秒的纳秒计数。但是,在为业务逻辑编写代码时,不应该考虑此实现细节。对于业务逻辑,调用LocalDateTime#toEpochSecond没有意义。
从技术上讲
因此,从技术上来说,您的问题的答案是,您的3小时增量(1_674_501_451L-1_674_512_251L)是由于JVM当前的默认时区使用了+03:00的偏移量,比UTC早3小时。因此,您调用LocalDateTime.now捕获了比UTC早3小时的日期和时间,但随后您请求
toEpochSecond,它将相同的日期和时间视为UTC**。
从逻辑上讲
当然,这个日期和时间并不代表UTC中的某个时刻,所以从逻辑上讲,您的代码是没有意义的,您不应该将LocalDateTime(这是一个非时刻)的历元计数与其他类(如Instant,这是一个时刻)进行比较。
换句话说,你是comparing apples and oranges

序列化日期-时间数据

那么,如果LocalDateTime#toEpochSecond不适合于业务逻辑,那么该类为什么要提供这样一个方法呢?
该方法对于序列化LocalDateTime值以进行存储或数据交换很有用。其他一些系统可能以这种方式显示日期时间值。

ISO 8601标准

但是,使用引用计数是一种很差的日期时间值通信方式。这些值是不明确的,因为它们的粒度是隐式的,而且它们特定的纪元参考点也是隐式的。而且,这样的值使人类读者难以验证和调试。
我强烈建议在Java之外存储或交换日期-时间值时使用标准的ISO 8601文本而不是count
2023年1月23日22时17分31秒
一般建议:* * 避免使用LocalDateTime类**,除非您 * 非常 * 清楚它的适当用法。
对于商业应用程序,我们通常会跟踪时刻。例如,"这个合同什么时候生效","这个员工什么时候被雇佣","这个房子什么时候结束购买"。所以不需要LocalDateTime
LocalDateTime的两个业务场景是(a)如果时区规则发生变化,我们希望时间浮动的预约,如诊所和沙龙预约,以及(b)这里我们指的是几个时刻,每个时刻都有相同的挂钟时间,但发生在时间线上的不同点,例如"中午在我们公司位于德里、杜塞尔多夫、和底特律。"。搜索栈溢出了解更多关于这一点,因为我和其他人已经张贴多次。
On Ideone.com,请参阅我在编写此答案时参考的一些代码。

相关问题