This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git


The following commit(s) were added to refs/heads/master by this push:
     new 040a649  Add and use PathUtils.isNewer(Path, ChronoZonedDateTime, 
LinkOption...) for more precision.
040a649 is described below

commit 040a649d19cc8f61b846592d73ba584193c6fd74
Author: Gary Gregory <gardgreg...@gmail.com>
AuthorDate: Tue Sep 14 17:15:31 2021 -0400

    Add and use PathUtils.isNewer(Path, ChronoZonedDateTime, LinkOption...)
    for more precision.
    
    - Add and use PathUtils.isNewer(Path, Path) for more precision.
    - Add and use FileUtils.isNewer(File, FileTime) for more precision.
    - Tailer uses more precise file time checks.
---
 src/changes/changes.xml                            |  9 ++-
 src/main/java/org/apache/commons/io/FileUtils.java | 44 ++++++++++-
 .../java/org/apache/commons/io/file/PathUtils.java | 90 ++++++++++++++++------
 .../commons/io/file/attribute/FileTimes.java       | 71 ++++++++++++++++-
 .../java/org/apache/commons/io/input/Tailer.java   |  9 ++-
 .../commons/io/FileUtilsFileNewerTestCase.java     | 73 ++++++++----------
 .../commons/io/file/attribute/FileTimesTest.java   | 44 +++++++++++
 7 files changed, 266 insertions(+), 74 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 010208d..4d34fdf 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -176,8 +176,13 @@ The <action> type attribute can be add,update,fix,remove.
         Add FileUtils.current().
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-        Add and use PathUtils.setLastModifiedTime(Path) for better precision.
-        Add and use PathUtils.setLastModifiedTime(Path, Path) for better 
precision.
+        Add and use PathUtils.setLastModifiedTime(Path) for more precision.
+        Add and use PathUtils.setLastModifiedTime(Path, Path) for more 
precision.
+      </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add and use PathUtils.isNewer(Path, ChronoZonedDateTime, 
LinkOption...) for more precision.
+        Add and use PathUtils.isNewer(Path, Path) for more precision.
+        Add and use FileUtils.isNewer(File, FileTime) for more precision.
       </action>
       <!-- UPDATE -->
       <action dev="ggregory" type="add" due-to="Gary Gregory">
diff --git a/src/main/java/org/apache/commons/io/FileUtils.java 
b/src/main/java/org/apache/commons/io/FileUtils.java
index 2a97da3..a14ea28 100644
--- a/src/main/java/org/apache/commons/io/FileUtils.java
+++ b/src/main/java/org/apache/commons/io/FileUtils.java
@@ -1561,6 +1561,22 @@ public class FileUtils {
     }
 
     /**
+     * Tests if the specified {@code File} is newer than the specified {@code 
FileTime}.
+     *
+     * @param file the {@code File} of which the modification date must be 
compared.
+     * @param fileTime the file time reference.
+     * @return true if the {@code File} exists and has been modified after the 
given {@code FileTime}.
+     * @throws IOException if an I/O error occurs.
+     * @throws NullPointerException if the file or local date is {@code null}.
+     *
+     * @since 2.12.0
+     */
+    public static boolean isFileNewer(final File file, final FileTime 
fileTime) throws IOException {
+        Objects.requireNonNull(file, "file");
+        return PathUtils.isNewer(file.toPath(), fileTime);
+    }
+
+    /**
      * Tests if the specified {@code File} is newer than the specified {@code 
ChronoLocalDate}
      * at the specified time.
      *
@@ -1637,7 +1653,12 @@ public class FileUtils {
      */
     public static boolean isFileNewer(final File file, final 
ChronoZonedDateTime<?> chronoZonedDateTime) {
         Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime");
-        return isFileNewer(file, chronoZonedDateTime.toInstant());
+        try {
+            return PathUtils.isNewer(file.toPath(), chronoZonedDateTime);
+        } catch (final IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
@@ -1666,7 +1687,12 @@ public class FileUtils {
      */
     public static boolean isFileNewer(final File file, final File reference) {
         requireExists(reference, "reference");
-        return isFileNewer(file, lastModifiedUnchecked(reference));
+        try {
+            return PathUtils.isNewer(file.toPath(), reference.toPath());
+        } catch (final IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
@@ -1681,7 +1707,12 @@ public class FileUtils {
      */
     public static boolean isFileNewer(final File file, final Instant instant) {
         Objects.requireNonNull(instant, "instant");
-        return isFileNewer(file, instant.toEpochMilli());
+        try {
+            return PathUtils.isNewer(file.toPath(), instant);
+        } catch (final IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
@@ -1695,7 +1726,12 @@ public class FileUtils {
      */
     public static boolean isFileNewer(final File file, final long timeMillis) {
         Objects.requireNonNull(file, "file");
-        return file.exists() && lastModifiedUnchecked(file) > timeMillis;
+        try {
+            return PathUtils.isNewer(file.toPath(), timeMillis);
+        } catch (final IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java 
b/src/main/java/org/apache/commons/io/file/PathUtils.java
index fc77ed0..ab63893 100644
--- a/src/main/java/org/apache/commons/io/file/PathUtils.java
+++ b/src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -49,6 +49,7 @@ import java.nio.file.attribute.PosixFileAttributes;
 import java.nio.file.attribute.PosixFilePermission;
 import java.time.Duration;
 import java.time.Instant;
+import java.time.chrono.ChronoZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -220,6 +221,20 @@ public final class PathUtils {
     }
 
     /**
+     * Compares the specified {@code Path}'s last modified time to the given 
file time.
+     *
+     * @param file the {@code Path} of which the modification date must be 
compared
+     * @param fileTime the time reference.
+     * @param options options indicating how symbolic links are handled been 
modified after the given time reference.
+     * @return See {@link FileTime#compareTo(FileTime)}
+     * @throws IOException if an I/O error occurs.
+     * @throws NullPointerException if the file is {@code null}
+     */
+    private static int compareLastModifiedTimeTo(final Path file, final 
FileTime fileTime, final LinkOption... options) throws IOException {
+        return Files.getLastModifiedTime(file, options).compareTo(fileTime);
+    }
+
+    /**
      * Copies a directory to another directory.
      *
      * @param sourceDirectory The source directory.
@@ -511,7 +526,7 @@ public final class PathUtils {
         if (path1 == null || path2 == null) {
             return false;
         }
-        if (Files.notExists(path1) && Files.notExists(path2)) {
+        if (notExists(path1) && notExists(path2)) {
             return true;
         }
         final RelativeSortedPaths relativeSortedPaths = new 
RelativeSortedPaths(path1, path2, Integer.MAX_VALUE, linkOptions, 
fileVisitOption);
@@ -769,20 +784,34 @@ public final class PathUtils {
      * Tests if the specified {@code Path} is newer than the specified time 
reference.
      *
      * @param file the {@code Path} of which the modification date must be 
compared
+     * @param czdt the time reference.
+     * @param options options indicating how symbolic links are handled been 
modified after the given time reference.
+     * @return true if the {@code Path} exists and has been modified after the 
given time reference.
+     * @throws IOException if an I/O error occurs.
+     * @throws NullPointerException if the file is {@code null}
+     * @since 2.12.0
+     */
+    public static boolean isNewer(final Path file, final 
ChronoZonedDateTime<?> czdt, final LinkOption... options) throws IOException {
+        Objects.requireNonNull(czdt, "czdt");
+        return isNewer(file, czdt.toInstant(), options);
+    }
+
+    /**
+     * Tests if the specified {@code Path} is newer than the specified time 
reference.
+     *
+     * @param file the {@code Path} of which the modification date must be 
compared
      * @param fileTime the time reference.
-     * @param options options indicating how symbolic links are handled * 
@return true if the {@code Path} exists and has
-     *        been modified after the given time reference.
+     * @param options options indicating how symbolic links are handled been 
modified after the given time reference.
      * @return true if the {@code Path} exists and has been modified after the 
given time reference.
      * @throws IOException if an I/O error occurs.
      * @throws NullPointerException if the file is {@code null}
      * @since 2.12.0
      */
     public static boolean isNewer(final Path file, final FileTime fileTime, 
final LinkOption... options) throws IOException {
-        Objects.requireNonNull(file, "file");
-        if (Files.notExists(file)) {
+        if (notExists(file)) {
             return false;
         }
-        return Files.getLastModifiedTime(file, options).compareTo(fileTime) > 
0;
+        return compareLastModifiedTimeTo(file, fileTime, options) > 0;
     }
 
     /**
@@ -798,11 +827,7 @@ public final class PathUtils {
      * @since 2.12.0
      */
     public static boolean isNewer(final Path file, final Instant instant, 
final LinkOption... options) throws IOException {
-        Objects.requireNonNull(file, "file");
-        if (Files.notExists(file)) {
-            return false;
-        }
-        return Files.getLastModifiedTime(file, 
options).toInstant().isAfter(instant);
+        return isNewer(file, FileTime.from(instant), options);
     }
 
     /**
@@ -822,6 +847,20 @@ public final class PathUtils {
     }
 
     /**
+     * Tests if the specified {@code Path} is newer than the reference {@code 
Path}.
+     *
+     * @param file      the {@code File} of which the modification date must 
be compared.
+     * @param reference the {@code File} of which the modification date is 
used.
+     * @return true if the {@code File} exists and has been modified more
+     * recently than the reference {@code File}.
+     * @throws IOException if an I/O error occurs.
+     * @since 2.12.0
+     */
+    public static boolean isNewer(final Path file, final Path reference) 
throws IOException {
+        return isNewer(file, Files.getLastModifiedTime(reference));
+    }
+
+    /**
      * Tests whether the specified {@code Path} is a regular file or not. 
Implemented as a null-safe delegate to
      * {@code Files.isRegularFile(Path path, LinkOption... options)}.
      *
@@ -837,6 +876,7 @@ public final class PathUtils {
         return path != null && Files.isRegularFile(path, options);
     }
 
+
     /**
      * Creates a new DirectoryStream for Paths rooted at the given directory.
      *
@@ -869,6 +909,10 @@ public final class PathUtils {
         // @formatter:on
     }
 
+    private static boolean notExists(final Path file) {
+        return Files.notExists(Objects.requireNonNull(file, "file"));
+    }
+
     /**
      * Returns true if the given options contain {@link 
StandardDeleteOption#OVERRIDE_READ_ONLY}.
      *
@@ -943,6 +987,17 @@ public final class PathUtils {
     }
 
     /**
+     * Sets the last modified time of the given file path to now.
+     *
+     * @param path The file path to set.
+     * @throws IOException if an I/O error occurs.
+     * @since 2.12.0
+     */
+    public static void setLastModifiedTime(final Path path) throws IOException 
{
+        Files.setLastModifiedTime(path, FileTime.from(Instant.now()));
+    }
+
+    /**
      * Sets the given {@code targetFile}'s last modified time to the value 
from {@code sourceFile}.
      *
      * @param sourceFile The source path to query.
@@ -958,17 +1013,6 @@ public final class PathUtils {
     }
 
     /**
-     * Sets the last modified time of the given file path to now.
-     *
-     * @param path The file path to set.
-     * @throws IOException if an I/O error occurs.
-     * @since 2.12.0
-     */
-    public static void setLastModifiedTime(final Path path) throws IOException 
{
-        Files.setLastModifiedTime(path, FileTime.from(Instant.now()));
-    }
-
-    /**
      * Sets the given Path to the {@code readOnly} value.
      * <p>
      * This behavior is OS dependent.
@@ -1109,7 +1153,7 @@ public final class PathUtils {
      * @throws NullPointerException if the file is {@code null}.
      * @since 2.12.0
      */
-    public static boolean waitFor(final Path file, final Duration timeout, 
LinkOption... options) {
+    public static boolean waitFor(final Path file, final Duration timeout, 
final LinkOption... options) {
         Objects.requireNonNull(file, "file");
         final Instant finishInstant = Instant.now().plus(timeout);
         boolean interrupted = false;
diff --git a/src/main/java/org/apache/commons/io/file/attribute/FileTimes.java 
b/src/main/java/org/apache/commons/io/file/attribute/FileTimes.java
index 72d92a9..ffc4c22 100644
--- a/src/main/java/org/apache/commons/io/file/attribute/FileTimes.java
+++ b/src/main/java/org/apache/commons/io/file/attribute/FileTimes.java
@@ -22,18 +22,85 @@ import java.time.Instant;
 
 /**
  * Helps use {@link FileTime}.
+ *
+ * @since 2.12.0
  */
 public class FileTimes {
 
     /**
-     * Constant for the 1970-01-01T00:00:00Z epoch time stamp attribute.
+     * Constant for the {@code 1970-01-01T00:00:00Z} epoch time stamp 
attribute.
      *
      * @see Instant#EPOCH
      */
     public static final FileTime EPOCH = FileTime.from(Instant.EPOCH);
 
+    /**
+     * Subtracts milliseconds from a source FileTime.
+     *
+     * @param fileTime The source FileTime.
+     * @param millisToSubtract The milliseconds to subtract.
+     * @return The resulting FileTime.
+     */
+    public static FileTime minusMillis(final FileTime fileTime, final long 
millisToSubtract) {
+        return 
FileTime.from(fileTime.toInstant().minusMillis(millisToSubtract));
+    }
+
+    /**
+     * Subtracts nanoseconds from a source FileTime.
+     *
+     * @param fileTime The source FileTime.
+     * @param nanosToSubtract The nanoseconds to subtract.
+     * @return The resulting FileTime.
+     */
+    public static FileTime minusNanos(final FileTime fileTime, final long 
nanosToSubtract) {
+        return FileTime.from(fileTime.toInstant().minusNanos(nanosToSubtract));
+    }
+
+    /**
+     * Subtracts seconds from a source FileTime.
+     *
+     * @param fileTime The source FileTime.
+     * @param secondsToSubtract The seconds to subtract.
+     * @return The resulting FileTime.
+     */
+    public static FileTime minusSeconds(final FileTime fileTime, final long 
secondsToSubtract) {
+        return 
FileTime.from(fileTime.toInstant().minusSeconds(secondsToSubtract));
+    }
+
+    /**
+     * Adds milliseconds to a source FileTime.
+     *
+     * @param fileTime The source FileTime.
+     * @param millisToAdd The milliseconds to add.
+     * @return The resulting FileTime.
+     */
+    public static FileTime plusMillis(final FileTime fileTime, final long 
millisToAdd) {
+        return FileTime.from(fileTime.toInstant().plusMillis(millisToAdd));
+    }
+
+    /**
+     * Adds nanoseconds from a source FileTime.
+     *
+     * @param fileTime The source FileTime.
+     * @param nanosToSubtract The nanoseconds to subtract.
+     * @return The resulting FileTime.
+     */
+    public static FileTime plusNanos(final FileTime fileTime, final long 
nanosToSubtract) {
+        return FileTime.from(fileTime.toInstant().plusNanos(nanosToSubtract));
+    }
+
+    /**
+     * Adds seconds to a source FileTime.
+     *
+     * @param fileTime The source FileTime.
+     * @param secondsToAdd The seconds to add.
+     * @return The resulting FileTime.
+     */
+    public static FileTime plusSeconds(final FileTime fileTime, final long 
secondsToAdd) {
+        return FileTime.from(fileTime.toInstant().plusSeconds(secondsToAdd));
+    }
+
     private FileTimes() {
         // No instances.
     }
-
 }
diff --git a/src/main/java/org/apache/commons/io/input/Tailer.java 
b/src/main/java/org/apache/commons/io/input/Tailer.java
index fc1e647..d8ca79c 100644
--- a/src/main/java/org/apache/commons/io/input/Tailer.java
+++ b/src/main/java/org/apache/commons/io/input/Tailer.java
@@ -26,6 +26,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.charset.Charset;
+import java.nio.file.attribute.FileTime;
 import java.time.Duration;
 
 import org.apache.commons.io.FileUtils;
@@ -437,7 +438,7 @@ public class Tailer implements Runnable {
     public void run() {
         RandomAccessFile reader = null;
         try {
-            long last = 0; // The last time the file was checked for changes
+            FileTime last = FileTime.fromMillis(0); // The last time the file 
was checked for changes
             long position = 0; // position within the file
             // Open the file
             while (getRun() && reader == null) {
@@ -451,7 +452,7 @@ public class Tailer implements Runnable {
                 } else {
                     // The current position in the file
                     position = end ? file.length() : 0;
-                    last = FileUtils.lastModified(file);
+                    last = FileUtils.lastModifiedFileTime(file);
                     reader.seek(position);
                 }
             }
@@ -486,7 +487,7 @@ public class Tailer implements Runnable {
                 if (length > position) {
                     // The file has more content than it did last time
                     position = readLines(reader);
-                    last = FileUtils.lastModified(file);
+                    last = FileUtils.lastModifiedFileTime(file);
                 } else if (newer) {
                     /*
                      * This can happen if the file is truncated or overwritten 
with the exact same length of
@@ -497,7 +498,7 @@ public class Tailer implements Runnable {
 
                     // Now we can read new lines
                     position = readLines(reader);
-                    last = FileUtils.lastModified(file);
+                    last = FileUtils.lastModifiedFileTime(file);
                 }
                 if (reOpen && reader != null) {
                     reader.close();
diff --git 
a/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java 
b/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java
index ead1179..82badd3 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java
@@ -23,8 +23,11 @@ import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
 import java.util.Date;
+import java.util.concurrent.TimeUnit;
 
+import org.apache.commons.io.file.attribute.FileTimes;
 import org.apache.commons.io.test.TestUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -50,25 +53,22 @@ public class FileUtilsFileNewerTestCase {
         testFile1 = new File(temporaryFolder, "file1-test.txt");
         testFile2 = new File(temporaryFolder, "file2-test.txt");
         if (!testFile1.getParentFile().exists()) {
-            throw new IOException("Cannot create file " + testFile1
-                    + " as the parent directory does not exist");
+            throw new IOException("Cannot create file " + testFile1 + " as the 
parent directory does not exist");
         }
-        try (final BufferedOutputStream output1 =
-                new 
BufferedOutputStream(Files.newOutputStream(testFile1.toPath()))) {
+        try (final BufferedOutputStream output1 = new 
BufferedOutputStream(Files.newOutputStream(testFile1.toPath()))) {
             TestUtils.generateTestData(output1, FILE1_SIZE);
         }
         if (!testFile2.getParentFile().exists()) {
-            throw new IOException("Cannot create file " + testFile2
-                    + " as the parent directory does not exist");
+            throw new IOException("Cannot create file " + testFile2 + " as the 
parent directory does not exist");
         }
-        try (final BufferedOutputStream output =
-                new 
BufferedOutputStream(Files.newOutputStream(testFile2.toPath()))) {
+        try (final BufferedOutputStream output = new 
BufferedOutputStream(Files.newOutputStream(testFile2.toPath()))) {
             TestUtils.generateTestData(output, FILE2_SIZE);
         }
     }
 
     /**
      * Tests the {@code isFileNewer(File, *)} methods which a "normal" file.
+     *
      * @throws IOException
      *
      * @see FileUtils#isFileNewer(File, long)
@@ -81,16 +81,17 @@ public class FileUtilsFileNewerTestCase {
             throw new IllegalStateException("The testFile1 should exist");
         }
 
-        final long fileLastModified = FileUtils.lastModified(testFile1);
-        final long TWO_SECOND = 2000;
+        final FileTime fileLastModified = 
Files.getLastModifiedTime(testFile1.toPath());
+        final long TWO_SECOND = 2;
 
-        testIsFileNewer("two second earlier is not newer" , testFile1, 
fileLastModified + TWO_SECOND, false);
-        testIsFileNewer("same time is not newer" , testFile1, 
fileLastModified, false);
-        testIsFileNewer("two second later is newer" , testFile1, 
fileLastModified - TWO_SECOND, true);
+        testIsFileNewer("two second earlier is not newer", testFile1, 
FileTimes.plusSeconds(fileLastModified, TWO_SECOND), false);
+        testIsFileNewer("same time is not newer", testFile1, fileLastModified, 
false);
+        testIsFileNewer("two second later is newer", testFile1, 
FileTimes.minusSeconds(fileLastModified, TWO_SECOND), true);
     }
 
     /**
      * Tests the {@code isFileNewer(File, *)} methods which a not existing 
file.
+     *
      * @throws IOException if an I/O error occurs.
      *
      * @see FileUtils#isFileNewer(File, long)
@@ -104,7 +105,7 @@ public class FileUtilsFileNewerTestCase {
             throw new IllegalStateException("The imaginary File exists");
         }
 
-        testIsFileNewer("imaginary file can be newer" , imaginaryFile, 
FileUtils.lastModified(testFile2), false);
+        testIsFileNewer("imaginary file can be newer", imaginaryFile, 
FileUtils.lastModifiedFileTime(testFile2), false);
     }
 
     /**
@@ -115,63 +116,57 @@ public class FileUtilsFileNewerTestCase {
      * <li>a {@code Date} which represents the time reference</li>
      * <li>a temporary file with the same last modification date as the time 
reference</li>
      * </ul>
-     * Then compares (with the needed {@code isFileNewer} method) the last 
modification date of
-     * the specified file with the specified time reference, the created 
{@code Date} and the temporary
-     * file.
-     * <br>
+     * Then compares (with the needed {@code isFileNewer} method) the last 
modification date of the specified file with the
+     * specified time reference, the created {@code Date} and the temporary 
file.
+     * <p>
      * The test is successful if the three comparisons return the specified 
wanted result.
      *
      * @param description describes the tested situation
      * @param file the file of which the last modification date is compared
-     * @param time the time reference measured in milliseconds since the epoch
+     * @param fileTime the time reference measured in milliseconds since the 
epoch
      * @param wantedResult the expected result
      * @throws IOException if an I/O error occurs.
-     *
-     * @see FileUtils#isFileNewer(File, long)
-     * @see FileUtils#isFileNewer(File, Date)
-     * @see FileUtils#isFileNewer(File, File)
      */
-    protected void testIsFileNewer(final String description, final File file, 
final long time, final boolean wantedResult) throws IOException  {
-        assertEquals(wantedResult, FileUtils.isFileNewer(file, time), 
description + " - time");
-        assertEquals(wantedResult, FileUtils.isFileNewer(file, new 
Date(time)), description + " - date");
+    protected void testIsFileNewer(final String description, final File file, 
final FileTime fileTime, final boolean wantedResult) throws IOException {
+        assertEquals(wantedResult, FileUtils.isFileNewer(file, fileTime), () 
-> description + " - FileTime");
+        assertEquals(wantedResult, FileUtils.isFileNewer(file, 
fileTime.toInstant()), () -> description + " - Instant");
 
         final File temporaryFile = testFile2;
-
-        temporaryFile.setLastModified(time);
-        assertEquals(time, FileUtils.lastModified(temporaryFile), "The 
temporary file hasn't the right last modification date");
-        assertEquals(wantedResult, FileUtils.isFileNewer(file, temporaryFile), 
description + " - file");
+        Files.setLastModifiedTime(temporaryFile.toPath(), fileTime);
+        assertEquals(fileTime, 
Files.getLastModifiedTime(temporaryFile.toPath()), "The temporary file hasn't 
the right last modification date");
+        assertEquals(wantedResult, FileUtils.isFileNewer(file, temporaryFile), 
() -> description + " - file");
     }
 
     /**
      * Tests the {@code isFileNewer(File, long)} method without specifying a 
{@code File}.
-     * <br>
+     * <p>
      * The test is successful if the method throws an {@code 
IllegalArgumentException}.
+     * </p>
      */
     @Test
     public void testIsFileNewerNoFile() {
-        assertThrows(NullPointerException.class, () -> 
FileUtils.isFileNewer(null,0),
-                "file");
+        assertThrows(NullPointerException.class, () -> 
FileUtils.isFileNewer(null, 0), "file");
     }
 
     /**
      * Tests the {@code isFileNewer(File, Date)} method without specifying a 
{@code Date}.
-     * <br>
+     * <p>
      * The test is successful if the method throws an {@code 
IllegalArgumentException}.
+     * </p>
      */
     @Test
     public void testIsFileNewerNoDate() {
-        assertThrows(NullPointerException.class, () -> 
FileUtils.isFileNewer(testFile1, (Date) null),
-                "date");
+        assertThrows(NullPointerException.class, () -> 
FileUtils.isFileNewer(testFile1, (Date) null), "date");
     }
 
     /**
      * Tests the {@code isFileNewer(File, File)} method without specifying a 
reference {@code File}.
-     * <br>
+     * <p>
      * The test is successful if the method throws an {@code 
IllegalArgumentException}.
+     * </p>
      */
     @Test
     public void testIsFileNewerNoFileReference() {
-        assertThrows(NullPointerException.class, () -> 
FileUtils.isFileNewer(testFile1, (File) null),
-                "reference");
+        assertThrows(NullPointerException.class, () -> 
FileUtils.isFileNewer(testFile1, (File) null), "reference");
     }
 }
diff --git 
a/src/test/java/org/apache/commons/io/file/attribute/FileTimesTest.java 
b/src/test/java/org/apache/commons/io/file/attribute/FileTimesTest.java
index 6e1aeea..a96565d 100644
--- a/src/test/java/org/apache/commons/io/file/attribute/FileTimesTest.java
+++ b/src/test/java/org/apache/commons/io/file/attribute/FileTimesTest.java
@@ -19,6 +19,8 @@ package org.apache.commons.io.file.attribute;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import java.time.Instant;
+
 import org.junit.jupiter.api.Test;
 
 /**
@@ -27,8 +29,50 @@ import org.junit.jupiter.api.Test;
 public class FileTimesTest {
 
     @Test
+    public void PlusMinusMillis() {
+        final int millis = 2;
+        assertEquals(Instant.EPOCH.plusMillis(millis), 
FileTimes.plusMillis(FileTimes.EPOCH, millis).toInstant());
+        assertEquals(Instant.EPOCH, FileTimes.plusMillis(FileTimes.EPOCH, 
0).toInstant());
+    }
+
+    @Test
     public void testEpoch() {
         assertEquals(0, FileTimes.EPOCH.toMillis());
     }
 
+    @Test
+    public void testMinusMillis() {
+        final int millis = 2;
+        assertEquals(Instant.EPOCH.minusMillis(millis), 
FileTimes.minusMillis(FileTimes.EPOCH, millis).toInstant());
+        assertEquals(Instant.EPOCH, FileTimes.minusMillis(FileTimes.EPOCH, 
0).toInstant());
+    }
+
+    @Test
+    public void testMinusNanos() {
+        final int millis = 2;
+        assertEquals(Instant.EPOCH.minusNanos(millis), 
FileTimes.minusNanos(FileTimes.EPOCH, millis).toInstant());
+        assertEquals(Instant.EPOCH, FileTimes.minusNanos(FileTimes.EPOCH, 
0).toInstant());
+    }
+
+    @Test
+    public void testMinusSeconds() {
+        final int seconds = 2;
+        assertEquals(Instant.EPOCH.minusSeconds(seconds), 
FileTimes.minusSeconds(FileTimes.EPOCH, seconds).toInstant());
+        assertEquals(Instant.EPOCH, FileTimes.minusSeconds(FileTimes.EPOCH, 
0).toInstant());
+    }
+
+    @Test
+    public void testPlusNanos() {
+        final int millis = 2;
+        assertEquals(Instant.EPOCH.plusNanos(millis), 
FileTimes.plusNanos(FileTimes.EPOCH, millis).toInstant());
+        assertEquals(Instant.EPOCH, FileTimes.plusNanos(FileTimes.EPOCH, 
0).toInstant());
+    }
+
+    @Test
+    public void testPlusSeconds() {
+        final int seconds = 2;
+        assertEquals(Instant.EPOCH.plusSeconds(seconds), 
FileTimes.plusSeconds(FileTimes.EPOCH, seconds).toInstant());
+        assertEquals(Instant.EPOCH, FileTimes.plusSeconds(FileTimes.EPOCH, 
0).toInstant());
+    }
+
 }

Reply via email to