JDK-8161942 : java.util.zip.ZipEntry.java not covering UpperLimit range of DOS epoch
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.jar
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-07-20
  • Updated: 2016-07-28
  • Resolved: 2016-07-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b129Fixed
Related Reports
Relates :  
Description
setTimeLocal(LocalDateTime time)/LocalDateTime getTimeLocal() from java.util.zip.ZipEntry.java not covering UpperLimit range of DOS epoch which is "1 January 1980 to 31 December 2099"

It looks like upper limit till year 2107 silently accepts
But with year 2108 and beyond shows the invalid range.

Whereas, the lower limit of year less than 1980 validation works well.



Comments
yes, as i said, the ZOS should output > 2038 extended timestamps to EXTID_NTFS format, instead of the info-zip's EXTID_EXTT
20-07-2016

If the date-time set is out of the range of the standard {@code * MS-DOS date and time format}, the time will also be stored into * zip file entry's extended timestamp fields in {@code optional * extra data} in UTC time. If spec would have not used the phrase "date-time set is out of the range MS-DOS date", This is not a concern. Also, jck tests for this feature is still evolving.
20-07-2016

it works for 2099 and 2107. we just hits the unix 2038 problem, when try to store the time into "unix timestamps" into the zip file when the timestamp is beyond the dos-time range. it's possible to not store the timestamp into ZipEntry.mtime in this case, but it has the benefit of keeping ZipEntry itself work (mean the set/getTimeLocal() behaves correctly), something just goes off when you write into/read from the ZIP file/stream. maybe the ZOS should go with EXTID_NTFS when beyond 2038 ... and ref?
20-07-2016

This is a pretty funny bug. It's hard even for this pedant to care about ZIP timestamps between 2099 and 2107.
20-07-2016

Below sample test can be used for reproducing. import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Files; import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; public class Main { private static TimeZone tz0 = TimeZone.getDefault(); public static void main(String[] args) throws Throwable{ try { testWithTimeZone_DOS_GreaterThan2017(); // testWithTimeZone_DOS_GreaterThan2017_zipfmt(); } finally { TimeZone.setDefault(tz0); } } public static void testWithTimeZone_DOS_GreaterThan2017() throws Throwable { LocalDateTime locdt_time = LocalDateTime.now(); TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); System.out.println("Year:2108"); testWithTZ_file_io_stream(tz, locdt_time.withYear(2108)); } public static void testWithTimeZone_DOS_GreaterThan2017_zipfmt() throws Throwable { LocalDateTime locdt_time = LocalDateTime.now(); TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); System.out.println("Year:2108"); testWithTZ_file(tz, locdt_time.withYear(2108)); } static void testWithTZ_file_io_stream(TimeZone tz, LocalDateTime locdt_time) throws Throwable { TimeZone.setDefault(tz); byte[] zbytes = getBytes(locdt_time); TimeZone.setDefault(tz0); chkWithZipFileFmt_iostream(zbytes, locdt_time); } static byte[] getBytes(LocalDateTime mtime) throws Throwable { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos); ZipEntry ze = new ZipEntry("Test.java"); ze.setTimeLocal(mtime); zos.putNextEntry(ze); zos.write(new byte[] { 10, 20, 30, 40}); zos.close(); return baos.toByteArray(); } static void chkWithZipFileFmt_iostream(byte[] zbytes, LocalDateTime expected) throws Throwable { ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zbytes)); ZipEntry ze = zis.getNextEntry(); zis.close(); System.out.println("Testing:"+ expected); check(ze, expected); } static void testWithTZ_file (TimeZone tz, LocalDateTime locdt_time) throws Throwable { TimeZone.setDefault(tz); byte[] zbytes = getBytes(locdt_time); TimeZone.setDefault(tz0); chkWithZipFileFmt(zbytes,locdt_time); } private static void chkWithZipFileFmt(byte[] zbytes, LocalDateTime expected) throws IOException { ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zbytes)); ZipEntry ze = zis.getNextEntry(); zis.close(); Path zpath = Paths.get(System.getProperty("test.dir", "."),"TestLocalTime.zip"); try { Files.copy(new ByteArrayInputStream(zbytes), zpath); ZipFile zf = new ZipFile(zpath.toFile()); ze = zf.getEntry("Test.java"); System.out.println("Testing:"+ expected); check(ze, expected); zf.close(); } finally { Files.deleteIfExists(zpath); } } static void check(ZipEntry ze, LocalDateTime expected) { LocalDateTime locdt_time = ze.getTimeLocal(); if (locdt_time.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1 != expected.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1) { throw new RuntimeException("Timestamp: storing mtime failed!"); } } }
20-07-2016

reference of epoch rang of DOS https://en.wikipedia.org/wiki/System_time#Operating_systems
20-07-2016