摘要: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
分析实验结果可知:
- 函数
System.currentTimeMillis()
与时区毫无瓜葛。 df.format(new Date())
的执行结果和时区休戚相关。其实,SimpleDateFormat的对象df可以调用函数df.setTimeZone(TimeZone.getTimeZone("UTC"))
设置时区。
关于时间的存储和显示问题,基于数据的存储和显示相分离是非常基础的设计原则,在数据库存储时间的时候,只保存表示绝对时间的Long型时间戳,不用顾虑应用服务器和数据库服务器的时区设置问题,在显示给用户的时候,根据用户设置的时区转换为字符串。
小结
函数System.currentTimeMillis()
获取的时间戳与时区无关。基于时间戳的时间存储不存在时区的问题,时区只与页面显示绑定。也就是说,在进行时间戳和日期之间的转换时,需要根据不同的时区进行计算,以防止出现时间偏差。