1818package org .apache .commons .io .file .attribute ;
1919
2020import java .io .IOException ;
21+ import java .math .BigDecimal ;
22+ import java .math .MathContext ;
23+ import java .math .RoundingMode ;
2124import java .nio .file .Files ;
2225import java .nio .file .Path ;
2326import java .nio .file .attribute .FileTime ;
3235 */
3336public final class FileTimes {
3437
38+ private static final MathContext MATH_CONTEXT = new MathContext (0 , RoundingMode .FLOOR );
39+
3540 /**
3641 * Constant for the {@code 1970-01-01T00:00:00Z} {@link Instant#EPOCH epoch} as a time stamp attribute.
3742 *
@@ -44,23 +49,30 @@ public final class FileTimes {
4449 *
4550 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724290%28v=vs.85%29.aspx">Windows File Times</a>
4651 * <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.
52+ * A file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated
53+ * Universal Time (UTC). This is the offset of Windows time 0 to Unix epoch in 100-nanosecond intervals.
5054 * </p>
5155 */
52- static final long WINDOWS_EPOCH_OFFSET = -116444736000000000L ;
56+ static final long UNIX_TO_NTFS_OFFSET = -116444736000000000L ;
57+
58+ private static final BigDecimal UNIX_TO_NTFS_OFFSET_BD = BigDecimal .valueOf (UNIX_TO_NTFS_OFFSET );
5359
5460 /**
5561 * The amount of 100-nanosecond intervals in one second.
5662 */
5763 private static final long HUNDRED_NANOS_PER_SECOND = TimeUnit .SECONDS .toNanos (1 ) / 100 ;
5864
65+ private static final BigDecimal HUNDRED_NANOS_PER_SECOND_BD = BigDecimal .valueOf (HUNDRED_NANOS_PER_SECOND );
66+
5967 /**
6068 * The amount of 100-nanosecond intervals in one millisecond.
6169 */
6270 static final long HUNDRED_NANOS_PER_MILLISECOND = TimeUnit .MILLISECONDS .toNanos (1 ) / 100 ;
6371
72+ private static final long HUNDRED = 100L ;
73+
74+ private static final BigDecimal HUNDRED_BD = BigDecimal .valueOf (HUNDRED );
75+
6476 /**
6577 * Converts standard Unix time (in seconds, UTC/GMT) to {@link FileTime}.
6678 *
@@ -100,7 +112,7 @@ public static boolean isUnixTime(final long seconds) {
100112 /**
101113 * Subtracts milliseconds from a source FileTime.
102114 *
103- * @param fileTime The source FileTime.
115+ * @param fileTime The source FileTime.
104116 * @param millisToSubtract The milliseconds to subtract.
105117 * @return The resulting FileTime.
106118 */
@@ -111,7 +123,7 @@ public static FileTime minusMillis(final FileTime fileTime, final long millisToS
111123 /**
112124 * Subtracts nanoseconds from a source FileTime.
113125 *
114- * @param fileTime The source FileTime.
126+ * @param fileTime The source FileTime.
115127 * @param nanosToSubtract The nanoseconds to subtract.
116128 * @return The resulting FileTime.
117129 */
@@ -122,7 +134,7 @@ public static FileTime minusNanos(final FileTime fileTime, final long nanosToSub
122134 /**
123135 * Subtracts seconds from a source FileTime.
124136 *
125- * @param fileTime The source FileTime.
137+ * @param fileTime The source FileTime.
126138 * @param secondsToSubtract The seconds to subtract.
127139 * @return The resulting FileTime.
128140 */
@@ -150,7 +162,7 @@ public static FileTime now() {
150162 * @see <a href="https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times">NTFS File Times</a>
151163 */
152164 public static Date ntfsTimeToDate (final long ntfsTime ) {
153- final long javaHundredNanos = Math .addExact (ntfsTime , WINDOWS_EPOCH_OFFSET );
165+ final long javaHundredNanos = Math .addExact (ntfsTime , UNIX_TO_NTFS_OFFSET );
154166 final long javaMillis = Math .floorDiv (javaHundredNanos , HUNDRED_NANOS_PER_MILLISECOND );
155167 return new Date (javaMillis );
156168 }
@@ -167,16 +179,23 @@ public static Date ntfsTimeToDate(final long ntfsTime) {
167179 * @see <a href="https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times">NTFS File Times</a>
168180 */
169181 public static FileTime ntfsTimeToFileTime (final long ntfsTime ) {
170- final long javaHundredsNanos = Math .addExact (ntfsTime , WINDOWS_EPOCH_OFFSET );
171- final long javaSeconds = Math .floorDiv (javaHundredsNanos , HUNDRED_NANOS_PER_SECOND );
172- final long javaNanos = Math .floorMod (javaHundredsNanos , HUNDRED_NANOS_PER_SECOND ) * 100 ;
173- return FileTime .from (Instant .ofEpochSecond (javaSeconds , javaNanos ));
182+ return FileTime .from (ntfsTimeToInstant (ntfsTime ));
183+ }
184+
185+ static Instant ntfsTimeToInstant (final BigDecimal ntfsTime ) {
186+ final BigDecimal javaHundredsNanos = ntfsTime .add (UNIX_TO_NTFS_OFFSET_BD );
187+ final BigDecimal [] dar = javaHundredsNanos .divideAndRemainder (HUNDRED_NANOS_PER_SECOND_BD , MATH_CONTEXT );
188+ return Instant .ofEpochSecond (dar [0 ].longValueExact (), dar [1 ].multiply (HUNDRED_BD ).longValueExact ());
189+ }
190+
191+ static Instant ntfsTimeToInstant (final long ntfsTime ) {
192+ return ntfsTimeToInstant (BigDecimal .valueOf (ntfsTime ));
174193 }
175194
176195 /**
177196 * Adds milliseconds to a source FileTime.
178197 *
179- * @param fileTime The source FileTime.
198+ * @param fileTime The source FileTime.
180199 * @param millisToAdd The milliseconds to add.
181200 * @return The resulting FileTime.
182201 */
@@ -187,7 +206,7 @@ public static FileTime plusMillis(final FileTime fileTime, final long millisToAd
187206 /**
188207 * Adds nanoseconds from a source FileTime.
189208 *
190- * @param fileTime The source FileTime.
209+ * @param fileTime The source FileTime.
191210 * @param nanosToSubtract The nanoseconds to subtract.
192211 * @return The resulting FileTime.
193212 */
@@ -198,7 +217,7 @@ public static FileTime plusNanos(final FileTime fileTime, final long nanosToSubt
198217 /**
199218 * Adds seconds to a source FileTime.
200219 *
201- * @param fileTime The source FileTime.
220+ * @param fileTime The source FileTime.
202221 * @param secondsToAdd The seconds to add.
203222 * @return The resulting FileTime.
204223 */
@@ -217,8 +236,7 @@ public static void setLastModifiedTime(final Path path) throws IOException {
217236 }
218237
219238 /**
220- * Converts {@link FileTime} to a {@link Date}. If the provided FileTime is {@code null}, the returned Date is also
221- * {@code null}.
239+ * Converts {@link FileTime} to a {@link Date}. If the provided FileTime is {@code null}, the returned Date is also {@code null}.
222240 *
223241 * @param fileTime the file time to be converted.
224242 * @return a {@link Date} which corresponds to the supplied time, or {@code null} if the time is {@code null}.
@@ -229,8 +247,7 @@ public static Date toDate(final FileTime fileTime) {
229247 }
230248
231249 /**
232- * Converts {@link Date} to a {@link FileTime}. If the provided Date is {@code null}, the returned FileTime is also
233- * {@code null}.
250+ * Converts {@link Date} to a {@link FileTime}. If the provided Date is {@code null}, the returned FileTime is also {@code null}.
234251 *
235252 * @param date the date to be converted.
236253 * @return a {@link FileTime} which corresponds to the supplied date, or {@code null} if the date is {@code null}.
@@ -251,7 +268,7 @@ public static FileTime toFileTime(final Date date) {
251268 */
252269 public static long toNtfsTime (final Date date ) {
253270 final long javaHundredNanos = date .getTime () * HUNDRED_NANOS_PER_MILLISECOND ;
254- return Math .subtractExact (javaHundredNanos , WINDOWS_EPOCH_OFFSET );
271+ return Math .subtractExact (javaHundredNanos , UNIX_TO_NTFS_OFFSET );
255272 }
256273
257274 /**
@@ -264,9 +281,13 @@ public static long toNtfsTime(final Date date) {
264281 * @return the NTFS time, 100-nanosecond units since 1 January 1601.
265282 */
266283 public static long toNtfsTime (final FileTime fileTime ) {
267- final Instant instant = fileTime .toInstant ();
268- final long javaHundredNanos = instant .getEpochSecond () * HUNDRED_NANOS_PER_SECOND + instant .getNano () / 100 ;
269- return Math .subtractExact (javaHundredNanos , WINDOWS_EPOCH_OFFSET );
284+ return toNtfsTime (fileTime .toInstant ());
285+ }
286+
287+ static long toNtfsTime (final Instant instant ) {
288+ final BigDecimal javaHundredNanos = BigDecimal .valueOf (instant .getEpochSecond ()).multiply (HUNDRED_NANOS_PER_SECOND_BD )
289+ .add (BigDecimal .valueOf (instant .getNano () / 100 ));
290+ return javaHundredNanos .subtract (UNIX_TO_NTFS_OFFSET_BD ).longValueExact ();
270291 }
271292
272293 /**
@@ -281,7 +302,7 @@ public static long toNtfsTime(final FileTime fileTime) {
281302 */
282303 public static long toNtfsTime (final long javaTime ) {
283304 final long javaHundredNanos = javaTime * HUNDRED_NANOS_PER_MILLISECOND ;
284- return Math .subtractExact (javaHundredNanos , WINDOWS_EPOCH_OFFSET );
305+ return Math .subtractExact (javaHundredNanos , UNIX_TO_NTFS_OFFSET );
285306 }
286307
287308 /**
0 commit comments