System.currentTimeMillis()与时区无关

发布时间 2023-08-13 12:16:18作者: 楼兰胡杨

摘要:System.currentTimeMillis()获取的时间戳与时区无关。

综述

  System.currentTimeMillis()经常被用来获取当前时间戳,单位是毫秒,可以用来计算当前年月日或者星期几等,可以方便地与Date进行转换,可以计算某个方法的耗时:

long curTime = System.currentTimeMillis();
doSth();
System.out.println("耗时 = " + (System.currentTimeMillis()-curTime));

  正因为该方法是当前时间节点与0时区(1970-01-01 00:00:00 +0:00)相差的毫秒数,所以在这个时间节点,无论在哪个时区获取时间戳,其值丝毫不差。

测试用例

  如何验证它不会因为时区不同而返回不同的数值呢?测试用例很简单:调用函数TimeZone.setDefault(TimeZone zone)初始化操作系统时区为上海,打印一次时间戳的计算结果,接着切换操作系统的时区到东京,再运行一次,得到时间戳2。时间戳2和时间戳1的差值,等于切换时区的耗时,看看此耗时是否非常地小;为了使得实验效果更理想,每次切换时区都打印时分秒格式的当前时间,而且加了一组巴黎时区的数据。

    public static void main(String[] args) throws InterruptedException {
        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        long timestamp1 = System.currentTimeMillis();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(df.format(new Date()));

        System.out.println("时间戳: " + timestamp1 + ",OS time zone: " + ZoneId.systemDefault());
        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Tokyo"));
        long timestamp2 = System.currentTimeMillis();
        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(df.format(new Date()));
        System.out.println("时间戳: " + timestamp2 + ",OS time zone: " + ZoneId.systemDefault());
        System.out.println("timestamp2 - timestamp1 = " + (timestamp2 - timestamp1));

        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
        long timestamp3 = System.currentTimeMillis();
        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(df.format(new Date()));
        System.out.println("时间戳: " + timestamp3 + ",OS time zone: " + ZoneId.systemDefault());
        System.out.println("timestamp3 - timestamp1 = " + (timestamp3 - timestamp1));
    }

实验结果如下:

2023-08-05 12:20:59
时间戳: 1691209259885,OS time zone: Asia/Shanghai
2023-08-05 13:21:00
时间戳: 1691209260033,OS time zone: Asia/Tokyo
timestamp2 - timestamp1 = 148
2023-08-05 06:21:00
时间戳: 1691209260035,OS time zone: Europe/Paris
timestamp3 - timestamp1 = 150

  分析实验结果可知:

  1. 函数System.currentTimeMillis()与时区毫无瓜葛。
  2. df.format(new Date()) 的执行结果和时区休戚相关。其实,SimpleDateFormat的对象df可以调用函数df.setTimeZone(TimeZone.getTimeZone("UTC"))设置时区。

  关于时间的存储和显示问题,基于数据的存储和显示相分离是非常基础的设计原则,在数据库存储时间的时候,只保存表示绝对时间的Long型时间戳,不用顾虑应用服务器和数据库服务器的时区设置问题,在显示给用户的时候,根据用户设置的时区转换为字符串。

小结

  函数System.currentTimeMillis()获取的时间戳与时区无关。基于时间戳的时间存储不存在时区的问题,时区只与页面显示绑定。也就是说,在进行时间戳和日期之间的转换时,需要根据不同的时区进行计算,以防止出现时间偏差。