Bug in File.getLastModified()

Seán Coffey sean.coffey at oracle.com
Fri Mar 31 18:01:32 UTC 2017


Hi Brian,

I think it's worth fixing unless there are objections. I see Stuart's 
comment about compatibility and wonder if we've any examples of such 
applications.

I just put together a patch [1] for this. I'm still figuring out how 
nanoseconds get recorded for macosx. stat64.st_mtimespec.tv_nsec seems 
to return 0 for me. We'd have to check the ppc/s390 ports also.

If successful, I might start an RFR for it. I think I found an issue 
with how Files.getLastModifiedTime handles a timestamp of Long.MAX_VALUE 
also. I might follow that up as a NIO issue. I don't think macosx 
returns millisecond resolution for the nio Files case either.

regards,
Sean.

[1]

diff --git a/src/solaris/native/java/io/UnixFileSystem_md.c 
b/src/solaris/native/java/io/UnixFileSystem_md.c
--- a/src/solaris/native/java/io/UnixFileSystem_md.c
+++ b/src/solaris/native/java/io/UnixFileSystem_md.c
@@ -208,7 +208,12 @@
      WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
          struct stat64 sb;
          if (stat64(path, &sb) == 0) {
-            rv = 1000 * (jlong)sb.st_mtime;
+            rv = (jlong)sb.st_mtime * 1000;
+#ifndef MACOSX
+    rv += (jlong)sb.st_mtim.tv_nsec / 1000000;
+#else
+    rv += (jlong)sb.st_mtimespec.tv_nsec / 1000000;
+#endif
          }
      } END_PLATFORM_STRING(env, path);
      return rv;
@@ -393,8 +398,11 @@

              /* Preserve access time */
              tv[0].tv_sec = sb.st_atime;
-            tv[0].tv_usec = 0;
-
+#ifndef MACOSX
+    tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
+#else
+    tv[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
+#endif
              /* Change last-modified time */
              tv[1].tv_sec = time / 1000;
              tv[1].tv_usec = (time % 1000) * 1000;
diff --git a/test/java/io/File/GetLastModified.java 
b/test/java/io/File/GetLastModified.java
new file mode 100644
--- /dev/null
+++ b/test/java/io/File/GetLastModified.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License 
version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8177809
+ * @summary File.lastModified() is losing milliseconds (always ends in 000)
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+public class GetLastModified {
+    private static final long[] LM = { 1490606336718L,
+        100L, 3000000000L /*, Long.MAX_VALUE */ };
+
+    public static void main(String[] args) throws IOException {
+        boolean fail = false;
+        File f = new File("GetLastModified.txt");
+        f.createNewFile();
+
+        for (int i = 0; i < LM.length; i++) {
+            f.setLastModified(LM[i]);
+            System.out.println("==============================");
+            System.out.printf("Test f.lastModified [%s]: %b\n",
+                f.lastModified(), f.lastModified() == LM[i]);
+            long filesMillis = 
Files.getLastModifiedTime(f.toPath()).toMillis();
+            System.out.printf("Test Files.getLastModifiedTime [%s]: %b\n",
+                filesMillis, filesMillis == LM[i]);
+            if (f.lastModified() != LM[i] || filesMillis != LM[i]) {
+                fail = true;
+            }
+        }
+        f.delete();
+        if (fail) {
+            throw new RuntimeException("Unexpected time stamps");
+        }
+    }
+}

On 31/03/17 16:03, Brian Burkhalter wrote:
> Hi Ricardo,
>
> Thanks for reading the specification verbiage closely. I think you 
> have a point. I’d like to read what others think about this.
>
> Regards,
>
> Brian
>
> On Mar 31, 2017, at 1:35 AM, Ricardo Almeida <ric.almeida at gmail.com 
> <mailto:ric.almeida at gmail.com>> wrote:
>
>> Just to add another though...
>>
>> I was just double-reading the documentation and it says:
>>
>> "All platforms support file-modification times to the nearest second,
>> but some provide more precision. The argument will be truncated to fit
>> the supported precision."
>>
>> So, if the platform supports it, the argument is NOT truncated... 
>> Next we have:
>>
>> "the next invocation of the lastModified() method will return the
>> (possibly truncated) time argument that was passed to this method"
>>
>> The way I read this sentence, it is 100% related with the first
>> sentence. It should return the value that was applied... if the system
>> supports only second precision, it is truncated. Otherwise, it should
>> return the not truncated value.
>



More information about the core-libs-dev mailing list