一、官方文档

参考自Java SE 8官方文档
在这里插入图片描述

方法功能:返回从1970年1月1日午夜(UTC)开始到当前时间的毫秒值.

其中,需要特别说明的地方

1.午夜(midnight)指的时间是 0时0分0秒,UTC表示该时间是0时区的时间
2.当前时间,不是指我们北京时间(UTC+8,东八区)的当前时间,而是0时区的当前时间。

例如,你现在的时间是1970-01-01 08:00:01(UTC+8),此刻0时区的时间是1970-01-01 00:00:01(UTC),共经过了1秒,所以计算机中存储的毫秒值是1000。

二、时间表示的起源及2038年问题

UNIX系统把1970年1月1日 00:00:00 GMT(GMT也表示0时区含义)作为时间的开始,称为纪元。

当时,操作系统是32位的,综合考虑决定使用32位的有符号数存储时间。对于1970年1月1日 00:00:00 UTC (等价我们的时间1970年1月1日 08:00:00 UTC+8)在计算机中存储为0。

注意,在UNIX中存储的值的单位是秒,在Java编程语言中的值的单位是毫秒。

用32位有符号能表示的最大值是01111111 11111111 11111111 11111111, 即214748367, 对应UTC时间2038年1月19日3时14分7秒。过了这个时间点,时间会溢出并变成10000000 00000000 00000000 00000000,即-214748368,对应的UTC时间1901年12月13日20时45分52秒,这样便会出现时间回归的现象,很多软件便会运行异常了。

要解决这个问题,最简单的方式是扩展UNIX时间的长度,用64位数字来表示它。64位二进制数的实际可用位数是63位。最大表示到公历的UTC时间292277026596年12月4日。如果那个时候人类文明还存在的话。公元纪年很可能已经因为太难用而被抛弃了。理想的情况是到2038年, 64位系统已经成为主流,从而避免特意去修正这个问题所需要的大量开销。否则,人们就必须把新的64位时间拆分成两部分并分别保存在两个变量里,这是一个麻烦而且效率低下的选择。

许多操作系统和编程语言都是以Unix为基础的,因此时间的起点,纪元通常和Unix选定的1970年1月1日 00:00:00 GMT一致。

三、Java中时间的表示

文章最开始就提到:时间是从1970年1月1日午夜(UTC)开始到当前时间的毫秒值。

Java中使用java.util.Date保存该毫秒值。

使用指定的long类型的毫秒值作为参数,初始化Date对象
在这里插入图片描述
默认构造函数使用当前时间的毫秒值初始化Date对象
在这里插入图片描述

另外,我们可以看到返回值是long类型,在Java中毫秒值是用64位存储的,不存在2038年的问题。

第一点,对于1970-01-01 00:00:01(UTC),毫秒值应该是1000,那么Java的实际存储值是1000吗?让我们来做个实验吧。


public static void main( String[] args ) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        // 设置时区0时区
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String source = "1970-01-01 00:00:01";
        Date data = sdf.parse(source);
        System.out.println("0时区时间:" + source +", 保存的毫秒值:" + data.getTime());
    }

运行结果,和我们期待的一样:
在这里插入图片描述

第二点,我们的东八区北京时间1970-01-01 08:00:01(UTC+8),存储值也是1000吗?注意,这里的时间是8小时0分1秒

    public static void main( String[] args ) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        // 设置时区为东八区
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        String source = "1970-01-01 08:00:01";
        Date data = sdf.parse(source);
        System.out.println("东八区时间:" + source +", 保存的毫秒值:" + data.getTime());
    }
}

运行结果如下图所示,验证了当前时间是指0时区的时间。

在这里插入图片描述

第三点,对于2038年1月19日3时14分7秒(UTC),在UNIX32位系统中保存为int的最大值214748367(秒),那么在Java的64位long类型中保存的值是214748367 * 1000 = 2147483671000毫秒吗?

     public static void main( String[] args ) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        // 设置时区0时区
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String source = "2038-01-19 03:14:07";
        Date data = sdf.parse(source);
        System.out.println("0时区时间:" + source +", 保存的毫秒值:" + data.getTime());
        System.out.println("int最大值*1000:" + (long)Integer.MAX_VALUE * 1000);
    }

运行结果,也和我们期待的一致

在这里插入图片描述


参考文章列表: 【[关于1970-1-1 00:00.000的知识](https://blog.csdn.net/tianzizhi/article/details/4547373) 】
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐