1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.io.file.attribute; 19 20 import java.io.IOException; 21 import java.nio.file.Files; 22 import java.nio.file.Path; 23 import java.nio.file.attribute.FileTime; 24 import java.time.Instant; 25 import java.util.Date; 26 import java.util.concurrent.TimeUnit; 27 28 /** 29 * Helps use {@link FileTime} and interoperate Date and NTFS times. 30 * 31 * @since 2.12.0 32 */ 33 public class FileTimes { 34 35 /** 36 * Constant for the {@code 1970-01-01T00:00:00Z} {@link Instant#EPOCH epoch} as a time stamp attribute. 37 * 38 * @see Instant#EPOCH 39 */ 40 public static final FileTime EPOCH = FileTime.from(Instant.EPOCH); 41 42 /** 43 * The offset of Windows time 0 to Unix epoch in 100-nanosecond intervals. 44 * 45 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724290%28v=vs.85%29.aspx">Windows File Times</a> 46 * <p> 47 * A file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 48 * A.M. January 1, 1601 Coordinated Universal Time (UTC). This is the offset of Windows time 0 to Unix epoch in 49 * 100-nanosecond intervals. 50 * </p> 51 */ 52 static final long WINDOWS_EPOCH_OFFSET = -116444736000000000L; 53 54 /** 55 * The amount of 100-nanosecond intervals in one second. 56 */ 57 private static final long HUNDRED_NANOS_PER_SECOND = TimeUnit.SECONDS.toNanos(1) / 100; 58 59 /** 60 * The amount of 100-nanosecond intervals in one millisecond. 61 */ 62 static final long HUNDRED_NANOS_PER_MILLISECOND = TimeUnit.MILLISECONDS.toNanos(1) / 100; 63 64 /** 65 * Subtracts milliseconds from a source FileTime. 66 * 67 * @param fileTime The source FileTime. 68 * @param millisToSubtract The milliseconds to subtract. 69 * @return The resulting FileTime. 70 */ minusMillis(final FileTime fileTime, final long millisToSubtract)71 public static FileTime minusMillis(final FileTime fileTime, final long millisToSubtract) { 72 return FileTime.from(fileTime.toInstant().minusMillis(millisToSubtract)); 73 } 74 75 /** 76 * Subtracts nanoseconds from a source FileTime. 77 * 78 * @param fileTime The source FileTime. 79 * @param nanosToSubtract The nanoseconds to subtract. 80 * @return The resulting FileTime. 81 */ minusNanos(final FileTime fileTime, final long nanosToSubtract)82 public static FileTime minusNanos(final FileTime fileTime, final long nanosToSubtract) { 83 return FileTime.from(fileTime.toInstant().minusNanos(nanosToSubtract)); 84 } 85 86 /** 87 * Subtracts seconds from a source FileTime. 88 * 89 * @param fileTime The source FileTime. 90 * @param secondsToSubtract The seconds to subtract. 91 * @return The resulting FileTime. 92 */ minusSeconds(final FileTime fileTime, final long secondsToSubtract)93 public static FileTime minusSeconds(final FileTime fileTime, final long secondsToSubtract) { 94 return FileTime.from(fileTime.toInstant().minusSeconds(secondsToSubtract)); 95 } 96 97 /** 98 * Obtains the current instant FileTime from the system clock. 99 * 100 * @return the current instant FileTime from the system clock. 101 */ now()102 public static FileTime now() { 103 return FileTime.from(Instant.now()); 104 } 105 106 /** 107 * Converts NTFS time (100 nanosecond units since 1 January 1601) to Java time. 108 * 109 * @param ntfsTime the NTFS time in 100 nanosecond units 110 * @return the Date 111 */ ntfsTimeToDate(final long ntfsTime)112 public static Date ntfsTimeToDate(final long ntfsTime) { 113 final long javaHundredNanos = Math.addExact(ntfsTime, WINDOWS_EPOCH_OFFSET); 114 final long javaMillis = Math.floorDiv(javaHundredNanos, HUNDRED_NANOS_PER_MILLISECOND); 115 return new Date(javaMillis); 116 } 117 118 /** 119 * Converts NTFS time (100-nanosecond units since 1 January 1601) to a FileTime. 120 * 121 * @param ntfsTime the NTFS time in 100-nanosecond units 122 * @return the FileTime 123 * 124 * @see #toNtfsTime(FileTime) 125 */ ntfsTimeToFileTime(final long ntfsTime)126 public static FileTime ntfsTimeToFileTime(final long ntfsTime) { 127 final long javaHundredsNanos = Math.addExact(ntfsTime, WINDOWS_EPOCH_OFFSET); 128 final long javaSeconds = Math.floorDiv(javaHundredsNanos, HUNDRED_NANOS_PER_SECOND); 129 final long javaNanos = Math.floorMod(javaHundredsNanos, HUNDRED_NANOS_PER_SECOND) * 100; 130 return FileTime.from(Instant.ofEpochSecond(javaSeconds, javaNanos)); 131 } 132 133 /** 134 * Adds milliseconds to a source FileTime. 135 * 136 * @param fileTime The source FileTime. 137 * @param millisToAdd The milliseconds to add. 138 * @return The resulting FileTime. 139 */ plusMillis(final FileTime fileTime, final long millisToAdd)140 public static FileTime plusMillis(final FileTime fileTime, final long millisToAdd) { 141 return FileTime.from(fileTime.toInstant().plusMillis(millisToAdd)); 142 } 143 144 /** 145 * Adds nanoseconds from a source FileTime. 146 * 147 * @param fileTime The source FileTime. 148 * @param nanosToSubtract The nanoseconds to subtract. 149 * @return The resulting FileTime. 150 */ plusNanos(final FileTime fileTime, final long nanosToSubtract)151 public static FileTime plusNanos(final FileTime fileTime, final long nanosToSubtract) { 152 return FileTime.from(fileTime.toInstant().plusNanos(nanosToSubtract)); 153 } 154 155 /** 156 * Adds seconds to a source FileTime. 157 * 158 * @param fileTime The source FileTime. 159 * @param secondsToAdd The seconds to add. 160 * @return The resulting FileTime. 161 */ plusSeconds(final FileTime fileTime, final long secondsToAdd)162 public static FileTime plusSeconds(final FileTime fileTime, final long secondsToAdd) { 163 return FileTime.from(fileTime.toInstant().plusSeconds(secondsToAdd)); 164 } 165 166 /** 167 * Sets the last modified time of the given file path to now. 168 * 169 * @param path The file path to set. 170 * @throws IOException if an I/O error occurs. 171 */ setLastModifiedTime(final Path path)172 public static void setLastModifiedTime(final Path path) throws IOException { 173 Files.setLastModifiedTime(path, now()); 174 } 175 176 /** 177 * Converts {@link FileTime} to a {@link Date}. If the provided FileTime is {@code null}, the returned Date is also 178 * {@code null}. 179 * 180 * @param fileTime the file time to be converted. 181 * @return a {@link Date} which corresponds to the supplied time, or {@code null} if the time is {@code null}. 182 * @see #toFileTime(Date) 183 */ toDate(final FileTime fileTime)184 public static Date toDate(final FileTime fileTime) { 185 return fileTime != null ? new Date(fileTime.toMillis()) : null; 186 } 187 188 /** 189 * Converts {@link Date} to a {@link FileTime}. If the provided Date is {@code null}, the returned FileTime is also 190 * {@code null}. 191 * 192 * @param date the date to be converted. 193 * @return a {@link FileTime} which corresponds to the supplied date, or {@code null} if the date is {@code null}. 194 * @see #toDate(FileTime) 195 */ toFileTime(final Date date)196 public static FileTime toFileTime(final Date date) { 197 return date != null ? FileTime.fromMillis(date.getTime()) : null; 198 } 199 200 /** 201 * Converts a {@link Date} to NTFS time. 202 * 203 * @param date the Date 204 * @return the NTFS time 205 */ toNtfsTime(final Date date)206 public static long toNtfsTime(final Date date) { 207 final long javaHundredNanos = date.getTime() * HUNDRED_NANOS_PER_MILLISECOND; 208 return Math.subtractExact(javaHundredNanos, WINDOWS_EPOCH_OFFSET); 209 } 210 211 /** 212 * Converts a {@link FileTime} to NTFS time (100-nanosecond units since 1 January 1601). 213 * 214 * @param fileTime the FileTime 215 * @return the NTFS time in 100-nanosecond units 216 */ toNtfsTime(final FileTime fileTime)217 public static long toNtfsTime(final FileTime fileTime) { 218 final Instant instant = fileTime.toInstant(); 219 final long javaHundredNanos = instant.getEpochSecond() * HUNDRED_NANOS_PER_SECOND + instant.getNano() / 100; 220 return Math.subtractExact(javaHundredNanos, WINDOWS_EPOCH_OFFSET); 221 } 222 FileTimes()223 private FileTimes() { 224 // No instances. 225 } 226 } 227