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"))); //东八区