View Javadoc
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 final 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       * Converts standard UNIX time (in seconds, UTC/GMT) to {@link FileTime}.
66       *
67       * @param time UNIX timestamp (seconds).
68       * @return the corresponding FileTime.
69       * @since 2.16.0
70       */
71      public static FileTime fromUnixTime(final long time) {
72          return FileTime.from(time, TimeUnit.SECONDS);
73      }
74  
75      /**
76       * Tests whether a FileTime can be safely represented in the standard UNIX time.
77       * <p>
78       * If the FileTime is null, this method returns true.
79       * </p>
80       *
81       * @param time the FileTime to evaluate, can be null.
82       * @return true if the time exceeds the minimum or maximum UNIX time, false otherwise.
83       * @since 2.16.0
84       */
85      public static boolean isUnixTime(final FileTime time) {
86          return isUnixTime(toUnixTime(time));
87      }
88  
89      /**
90       * Tests whether a given number of seconds (since Epoch) can be safely represented in the standard UNIX time.
91       *
92       * @param seconds the number of seconds (since Epoch) to evaluate.
93       * @return true if the time can be represented in the standard UNIX time, false otherwise.
94       * @since 2.16.0
95       */
96      public static boolean isUnixTime(final long seconds) {
97          return Integer.MIN_VALUE <= seconds && seconds <= Integer.MAX_VALUE;
98      }
99  
100 
101     /**
102      * Subtracts milliseconds from a source FileTime.
103      *
104      * @param fileTime The source FileTime.
105      * @param millisToSubtract The milliseconds to subtract.
106      * @return The resulting FileTime.
107      */
108     public static FileTime minusMillis(final FileTime fileTime, final long millisToSubtract) {
109         return FileTime.from(fileTime.toInstant().minusMillis(millisToSubtract));
110     }
111 
112     /**
113      * Subtracts nanoseconds from a source FileTime.
114      *
115      * @param fileTime The source FileTime.
116      * @param nanosToSubtract The nanoseconds to subtract.
117      * @return The resulting FileTime.
118      */
119     public static FileTime minusNanos(final FileTime fileTime, final long nanosToSubtract) {
120         return FileTime.from(fileTime.toInstant().minusNanos(nanosToSubtract));
121     }
122 
123     /**
124      * Subtracts seconds from a source FileTime.
125      *
126      * @param fileTime The source FileTime.
127      * @param secondsToSubtract The seconds to subtract.
128      * @return The resulting FileTime.
129      */
130     public static FileTime minusSeconds(final FileTime fileTime, final long secondsToSubtract) {
131         return FileTime.from(fileTime.toInstant().minusSeconds(secondsToSubtract));
132     }
133 
134     /**
135      * Obtains the current instant FileTime from the system clock.
136      *
137      * @return the current instant FileTime from the system clock.
138      */
139     public static FileTime now() {
140         return FileTime.from(Instant.now());
141     }
142 
143     /**
144      * Converts NTFS time (100 nanosecond units since 1 January 1601) to Java time.
145      *
146      * @param ntfsTime the NTFS time in 100 nanosecond units
147      * @return the Date
148      */
149     public static Date ntfsTimeToDate(final long ntfsTime) {
150         final long javaHundredNanos = Math.addExact(ntfsTime, WINDOWS_EPOCH_OFFSET);
151         final long javaMillis = Math.floorDiv(javaHundredNanos, HUNDRED_NANOS_PER_MILLISECOND);
152         return new Date(javaMillis);
153     }
154 
155     /**
156      * Converts NTFS time (100-nanosecond units since 1 January 1601) to a FileTime.
157      *
158      * @param ntfsTime the NTFS time in 100-nanosecond units
159      * @return the FileTime
160      *
161      * @see #toNtfsTime(FileTime)
162      */
163     public static FileTime ntfsTimeToFileTime(final long ntfsTime) {
164         final long javaHundredsNanos = Math.addExact(ntfsTime, WINDOWS_EPOCH_OFFSET);
165         final long javaSeconds = Math.floorDiv(javaHundredsNanos, HUNDRED_NANOS_PER_SECOND);
166         final long javaNanos = Math.floorMod(javaHundredsNanos, HUNDRED_NANOS_PER_SECOND) * 100;
167         return FileTime.from(Instant.ofEpochSecond(javaSeconds, javaNanos));
168     }
169 
170     /**
171      * Adds milliseconds to a source FileTime.
172      *
173      * @param fileTime The source FileTime.
174      * @param millisToAdd The milliseconds to add.
175      * @return The resulting FileTime.
176      */
177     public static FileTime plusMillis(final FileTime fileTime, final long millisToAdd) {
178         return FileTime.from(fileTime.toInstant().plusMillis(millisToAdd));
179     }
180 
181     /**
182      * Adds nanoseconds from a source FileTime.
183      *
184      * @param fileTime The source FileTime.
185      * @param nanosToSubtract The nanoseconds to subtract.
186      * @return The resulting FileTime.
187      */
188     public static FileTime plusNanos(final FileTime fileTime, final long nanosToSubtract) {
189         return FileTime.from(fileTime.toInstant().plusNanos(nanosToSubtract));
190     }
191 
192     /**
193      * Adds seconds to a source FileTime.
194      *
195      * @param fileTime The source FileTime.
196      * @param secondsToAdd The seconds to add.
197      * @return The resulting FileTime.
198      */
199     public static FileTime plusSeconds(final FileTime fileTime, final long secondsToAdd) {
200         return FileTime.from(fileTime.toInstant().plusSeconds(secondsToAdd));
201     }
202 
203     /**
204      * Sets the last modified time of the given file path to now.
205      *
206      * @param path The file path to set.
207      * @throws IOException if an I/O error occurs.
208      */
209     public static void setLastModifiedTime(final Path path) throws IOException {
210         Files.setLastModifiedTime(path, now());
211     }
212 
213     /**
214      * Converts {@link FileTime} to a {@link Date}. If the provided FileTime is {@code null}, the returned Date is also
215      * {@code null}.
216      *
217      * @param fileTime the file time to be converted.
218      * @return a {@link Date} which corresponds to the supplied time, or {@code null} if the time is {@code null}.
219      * @see #toFileTime(Date)
220      */
221     public static Date toDate(final FileTime fileTime) {
222         return fileTime != null ? new Date(fileTime.toMillis()) : null;
223     }
224 
225     /**
226      * Converts {@link Date} to a {@link FileTime}. If the provided Date is {@code null}, the returned FileTime is also
227      * {@code null}.
228      *
229      * @param date the date to be converted.
230      * @return a {@link FileTime} which corresponds to the supplied date, or {@code null} if the date is {@code null}.
231      * @see #toDate(FileTime)
232      */
233     public static FileTime toFileTime(final Date date) {
234         return date != null ? FileTime.fromMillis(date.getTime()) : null;
235     }
236 
237     /**
238      * Converts a {@link Date} to NTFS time.
239      *
240      * @param date the Date
241      * @return the NTFS time
242      */
243     public static long toNtfsTime(final Date date) {
244         final long javaHundredNanos = date.getTime() * HUNDRED_NANOS_PER_MILLISECOND;
245         return Math.subtractExact(javaHundredNanos, WINDOWS_EPOCH_OFFSET);
246     }
247 
248     /**
249      * Converts a {@link FileTime} to NTFS time (100-nanosecond units since 1 January 1601).
250      *
251      * @param fileTime the FileTime
252      * @return the NTFS time in 100-nanosecond units
253      */
254     public static long toNtfsTime(final FileTime fileTime) {
255         final Instant instant = fileTime.toInstant();
256         final long javaHundredNanos = instant.getEpochSecond() * HUNDRED_NANOS_PER_SECOND + instant.getNano() / 100;
257         return Math.subtractExact(javaHundredNanos, WINDOWS_EPOCH_OFFSET);
258     }
259 
260     /**
261      * Converts Java time (milliseconds since Epoch) to NTFS time.
262      *
263      * @param javaTime the Java time
264      * @return the NTFS time
265      * @since 2.16.0
266      */
267     public static long toNtfsTime(final long javaTime) {
268         final long javaHundredNanos = javaTime * HUNDRED_NANOS_PER_MILLISECOND;
269         return Math.subtractExact(javaHundredNanos, WINDOWS_EPOCH_OFFSET);
270     }
271 
272     /**
273      * Converts {@link FileTime} to standard UNIX time in seconds.
274      * <p>
275      * The returned seconds value may lie out of bounds of UNIX time. Check with {@link FileTimes#isUnixTime(long)}.
276      * </p>
277      *
278      * @param fileTime the original FileTime.
279      * @return the UNIX timestamp or 0 if the input is null.
280      * @see #isUnixTime(long)
281      * @since 2.16.0
282      */
283     public static long toUnixTime(final FileTime fileTime) {
284         return fileTime != null ? fileTime.to(TimeUnit.SECONDS) : 0;
285     }
286 
287     private FileTimes() {
288         // No instances.
289     }
290 }