在计算机中,每个文件都一个时间戳,之前遇到过一个关于文件时间戳的问题,这里记录下来分享给大家。

首先,遇到的问题的原型是:在一段Java程序中,通过Java的File.lastModified API去获得一个文件的时间戳,示例代码如下:

ClassLoader classLoader = DataMigrationController.class.getClassLoader();
URL url = classLoader.getResource("./application.properties");
File file = new File(url.toURI());
System.out.println(file + ": " + file.lastModified() + "->" + new Date(file.lastModified()));

URL url2 = classLoader.getResource("./bootstrap.properties");
File file2 = new File(url2.toURI());
System.out.println(file2 + ": " + file2.lastModified() + "->" + new Date(file2.lastModified()));

Date date = new Date();
System.out.println("current date: " + System.currentTimeMillis() + "->" + date);

当我在本地机器(成都)运行这段程序时,得到的结果如下:

application.properties: 1558083157000->Fri May 17 16:52:37 CST 2019

bootstrap.properties: 1558083157000->Fri May 17 16:52:37 CST 2019

current date: 1558083181463->Fri May 17 16:53:01 CST 2019

但是,当我把这段程序打好包(jar)部署到服务器上(两分钟之内),运行这段程序时,却得到如下结果(我expect得到的文件的时间戳和本地应该一致):

application.properties: 1558111956000->Fri May 17 16:52:36 UTC 2019

bootstrap.properties: 1558111956000->Fri May 17 16:52:36 UTC 2019

current date: 1558083328412->Fri May 17 08:55:28 UTC 2019

从上面的结果可以看出,得到的两个文件的时间戳比服务器上当时的时间还要晚,这很奇怪,怎么拿到了一个未来的时间?

起初怀疑是不是机器的时钟有问题。通过打印出来的当前时间来看,本地时间(Fri May 17 16:53:01 CST 2019)和服务器时间(Fri May 17 08:55:28 UTC 2019)是吻合的,说明时钟是没有问题。

后来发现,根本原因是压缩文件中的子文件的时间戳没有时区的信息,只有日期+时间的信息。具体出处可见(https://en.wikipedia.org/wiki/Zip_(file_format))中的一段话:

The ZIP format has no notion of time zone, so timestamps are only meaningful if it is known what time zone they were created in.

所以当在服务器上运行这段程序时,jar包解压,压缩文件里面的子文件的时间戳变成日期+时间+新的时区,即是我们看到的日期+时间没变,只是时区变成了服务器的时区UTC。

最后,下图展示了文件的时间戳在这个过程中的变化。

总结:当需要根据文件的时间戳来实现某些功能时,需要注意压缩文件中的子文件的时间戳没有时区的信息,只有日期+时间的信息。