Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8335398

Files.setLastModifiedTime() fails when last modified time before Jan 1 1970

XMLWordPrintable

    • generic
    • linux_ubuntu

      ADDITIONAL SYSTEM INFORMATION :
      $ java -version
      openjdk version "21.0.2" 2024-01-16
      OpenJDK Runtime Environment (build 21.0.2+13-Ubuntu-122.04.1)
      OpenJDK 64-Bit Server VM (build 21.0.2+13-Ubuntu-122.04.1, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      If the argument of Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(millis)) is negative and contains milliseconds, the file becomes the timestamp "Jan 1 1970", i.e. filetime is asumed as `0L`

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
          Calendar cal = Calendar.getInstance();
          cal.set(1960, 10-1, 12, 13, 25, 00);
          long millis = cal.getTimeInMillis();
          Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(millis));

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The timestamp of the file should be "Oct 12 1960 13:25:00".
      ACTUAL -
      The timestamp of the file is "Jan 1 1970 00:00:00".

      ---------- BEGIN SOURCE ----------
      import java.io.*;
      import java.nio.file.*;
      import java.nio.file.attribute.*;
      import java.time.*;
      import java.util.*;


      public class FileTimesFromCalendar {

        static long getCalendarMillis(int year) {
          Calendar cal = Calendar.getInstance();
          cal.set(year, 10-1, 12, 13, 25, 00);
          return cal.getTimeInMillis();
        }
        static long getDateMillis(int year) {
          return switch (year) {
            case 1960 -> Date.parse("12 Oct 1960 13:25:00");
            case 1980 -> Date.parse("12 Oct 1980 13:25:00");
            default -> (new Date()).getTime();
          };
        }
        static long getInstantMillis(int year) {
          Instant instant = ZonedDateTime.of(year, 10, 12, 13, 25, 00, 0, ZoneId.of("CET")).toInstant();
          return instant.toEpochMilli();
        }
        static void touch(long millis) throws IOException {
          final File parent = new File("log/FileTimes"), file;
          parent.mkdirs();
          try (FileOutputStream out = new FileOutputStream(file = new File(parent, "FileTime"))) {
            out.close();
            Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(millis));
            System.out.println("Date of file: "+new Date(file.lastModified()));
          }
        }
        static void touch(Instant instant) throws IOException {
          final File parent = new File("log/FileTimes"), file;
          parent.mkdirs();
          try (FileOutputStream out = new FileOutputStream(file = new File(parent, "FileTime"))) {
            out.close();
            Files.setLastModifiedTime(file.toPath(), FileTime.from(instant));
            System.out.println("Date of file: "+new Date(file.lastModified()));
          }
        }

        public static void main(String[] args) throws IOException, InterruptedException {
          for (int i=0; i<3; i++) {
            System.out.println("Negative Millis ...");
            long millis = getDateMillis(1960);
            System.out.println("Millies from Date: "+millis);
            touch(millis);
            millis = getCalendarMillis(1960);
            System.out.println("Millies from Calendar: "+millis);
            touch(millis);
            long rmillis = millis / 1000 * 1000 - 1000;
            System.out.println("Millies from Cal rounded down: "+rmillis);
            touch(rmillis);
            rmillis = Math.floorDiv(millis, 1000) * 1000;
            System.out.println("Millies from floorDiv(Cal): "+rmillis);
            touch(rmillis);
            millis = getInstantMillis(1960);
            System.out.println("Millies from Instant: "+millis);
            touch(millis);
            Instant instant = Instant.ofEpochSecond(-290950500L, 12345678L);
            System.out.println("Millies from Instant with nanos: "+instant.toEpochMilli());
            touch(instant.toEpochMilli());
            System.out.println("touch from Instant directly: "+instant);
            touch(instant);
            System.out.println("Positive Millis ...");
            millis = getDateMillis(1980);
            System.out.println("Millies from Date: "+millis);
            touch(millis);
            millis = getCalendarMillis(1980);
            System.out.println("Millies from Calendar: "+millis);
            touch(millis);
            rmillis = millis / 1000 * 1000;
            System.out.println("Millies from Cal rounded down: "+rmillis);
            touch(rmillis);
            rmillis = Math.floorDiv(millis, 1000) * 1000;
            System.out.println("Millies from floorDiv(Cal): "+rmillis);
            touch(rmillis);
            millis = getInstantMillis(1980);
            System.out.println("Millies from Instant: "+millis);
            touch(rmillis);

            Thread.sleep(250);
            System.out.println();
          }
        }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      // round down *absolutely* – for positive and negative values – to seconds with:
      millis = Math.floorDiv(millis, 1000) * 1000;

      FREQUENCY : always


        1. FileTimesFromCalendar.java
          4 kB
          Andrew Wang
        2. test.c
          0.5 kB
          Brian Burkhalter

            bpb Brian Burkhalter
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: