java中的时间与时区:LocalDateTime和Date

LocalDateTime

LocalDateTime本身不包含时区信息,它存储的是年、月、日、时分秒,纳秒这样的数字。
在不同的时区下,这样的数字代表不同的时间。

比如一个LocalDateTime存储2020-01-01 08:00:00,这里省略纳秒。
对北京和东京的人来看这个时间,都认为是本地时间的话,在真实时间上,因为时区的差异,其实是相差1个小时的时间的。

构造函数

既然不带时区,那么考虑LocalDateTime的构造函数:

LocalDateTime dtUtc = LocalDateTime.now(ZoneOffset.UTC);

为什么这里又有时区了呢?其实这是一个方便的方法:

如果只是为了获取当前系统所在默认时区的一个本地时间,那么用LocalDateTime.now()无参数构造方法即可,而如果我想知道现在在UTC时区那里本地显示的是什么时间,就可以用LocalDateTime.now(ZoneOffset.UTC)这个构造方法了。

所以对于我们东八区来说:


//假如这个时间是:2020-01-01 10:00:00
LocalDateTime dtLocal = LocalDateTime.now();

//那么这个时间就会存储:2020-01-01 02:00:00,提前8个小时
LocalDateTime dtUtc = LocalDateTime.now(ZoneOffset.UTC);

在构造后,LocalDateTime同样不携带时区信息,仍然只是表示一个显示时间而已。

Date

Date存储的是一个毫秒数,准确说是从1970-01-01 00:00:00到现在经过的毫秒数。
而这个毫秒数是有时区的,它存储的永远是现在针对UTC时区时的1970年零点,经过的毫秒数。怎么理解?

比如两个程序员在同一时刻,一个在英国,一个在中国,同时调用new Date(),那么此时Date中存储的毫秒数是完全相同的(当然是理想情况的同时,以及系统没有误差)。所不同的是在输出时,GMT0时区,直接使用这个毫秒数计算得到显示时间,而北京GMT+8显示时,会在这个时间上增加8小时,即时区偏移。

所以如下两个格式化类型,在当前东八区的使用场景,输出实际是一样的:

        SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     // 北京
        bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));  // 设置北京时区

      SimpleDateFormat dftSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     // 不设置时区

构造

因为Date有时区信息,所以构造Date也就需要时区信息。
因此,不能直接从LocalDateTime转换成Date,因为无法确定这个LodalDateTime究竟是哪个时区的这个时间。
而要借助Instant,因为Instant也代表从UTC开始的一个偏移时间。

LocalDateTime dt  = LocalDateTime.now();
Date dt2 = Date.from(dt.toInstant(ZoneOffset.of("+8"))); //东八区

输出

posted @ 2020-07-07 14:39  mosakashaka  阅读(17915)  评论(0编辑  收藏  举报