这是针对此处描述的再现性问题的建议修复 https://github.com/spring-projects/spring-boot/issues/34424
[spring-projects/spring-boot]修复插件时区依赖性
回答
我在本地安装了这个版本的插件,然后当我在复制项目中使用该版本时,我实际上得到了正确的时间戳,并且所有文件(使用 docker 中的所有时区)都是二进制相同的,并且时间戳看起来与配置的完全相同:2011- 11-11 22:22 。
https://github.com/nielsbasjes/BugreportSpringPluginTimezone
@nielsbasjes 我不认为像这样操纵时区是解决问题的正确方法。
查看.jar.original
复制示例中的文件,相同的时间戳应用于两个 jar,与本地时区无关。所以 Maven 正在做正确的事情。 Maven用来解析的代码project.build.outputTimeStamp
在这里:https://github.com/apache/maven-archiver/blob/maven-archiver-3.6.0/src/main/java/org/apache/maven/archiver/MavenArchiver .java#L886-L887。
与 Maven 不同,Spring Boot在解析日期withOffsetSameInstant(ZoneOffset.UTC)
后不会应用修饰符: https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring -boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java#L238。如果应用此修改器可以解决问题,那么对我来说它看起来是一个更干净的解决方案。OffsetDateTime.parse(outputTimeStamp)
您想尝试一下这个改变吗?
问题不在于时间戳的解析。这样做是正确的。时区是提供的时间戳的一部分(在我的示例中为“Z”)并且已正确处理。
然后,解析的时间戳被保存在一个实例中,该实例java.nio.file.attribute.FileTime
将时间戳本质上存储为纪元(即没有任何时区)。
该提议withOffsetSameInstant(ZoneOffset.UTC)
并未解决此问题,因为这不会更改复制到 FileTime 实例中的基础纪元值。
然后,Zip 创建代码(来自 commons-compress)使用基于系统默认时区的 Calendar 实例将纪元转换为其他内容。
据我所知,Spring 项目中的所有代码都正确处理了时间戳。
另外:可以提供所需的时间戳作为纪元,但纪元不能有时间戳,因此必须选择时区。当前的选择是本地系统时区,我的建议是强制(或可配置?)将其设置为 UTC 时区。
我想知道我们是否可以在JarWriter.writeToArchive(...)中更改此逻辑,以便jarEntry.setLastModifiedTime
基于.这样我们就可以写出一个偏移时间,并知道将其再次改回来。this.lastModifiedTime
Calendar.getInstance()
ZipUtil.toDosTime
@philwebb所以您使用当前时区来移动纪元时间戳,因为您希望底层代码将其再次移回?我会投票反对这样的代码。
是的。我更喜欢它的原因是因为TimeZone.setDefault(...)
更改了整个 JVM 的默认时区。如果 Maven 在另一个线程中(现在或将来)做其他事情,那么默认时区可能会在它的脚下发生变化。
TimeZone.setDefault(...)
更改整个 JVM 的默认时区
这也是我担心的,这可能会产生难以诊断的不可预测的副作用。
是的,确实如此。也许将此插件标记为非线程安全?
明天我会看看是否能让这个令人讨厌的时移工作变得可靠。说到时区..这里已经是明天了...
我发现 javadoc 比setTime
更好,setLastModifiedTime
并且实际上描述了在写入值时使用默认时区。我已经改用这种方法并采用了转变方法。该修复位于提交 998d59b7ac1a75b26634e4fd2843a7833e554840 中。
感谢您提出问题并提供分析。