001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.io.file.attribute; 019 020import java.io.IOException; 021import java.nio.file.Files; 022import java.nio.file.Path; 023import java.nio.file.attribute.FileTime; 024import java.time.Instant; 025import java.util.Date; 026import java.util.concurrent.TimeUnit; 027 028/** 029 * Helps use {@link FileTime} and interoperate Date and NTFS times. 030 * 031 * @since 2.12.0 032 */ 033public final class FileTimes { 034 035 /** 036 * Constant for the {@code 1970-01-01T00:00:00Z} {@link Instant#EPOCH epoch} as a time stamp attribute. 037 * 038 * @see Instant#EPOCH 039 */ 040 public static final FileTime EPOCH = FileTime.from(Instant.EPOCH); 041 042 /** 043 * The offset of Windows time 0 to UNIX epoch in 100-nanosecond intervals. 044 * 045 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724290%28v=vs.85%29.aspx">Windows File Times</a> 046 * <p> 047 * A file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 048 * A.M. January 1, 1601 Coordinated Universal Time (UTC). This is the offset of Windows time 0 to UNIX epoch in 049 * 100-nanosecond intervals. 050 * </p> 051 */ 052 static final long WINDOWS_EPOCH_OFFSET = -116444736000000000L; 053 054 /** 055 * The amount of 100-nanosecond intervals in one second. 056 */ 057 private static final long HUNDRED_NANOS_PER_SECOND = TimeUnit.SECONDS.toNanos(1) / 100; 058 059 /** 060 * The amount of 100-nanosecond intervals in one millisecond. 061 */ 062 static final long HUNDRED_NANOS_PER_MILLISECOND = TimeUnit.MILLISECONDS.toNanos(1) / 100; 063 064 /** 065 * Converts standard UNIX time (in seconds, UTC/GMT) to {@link FileTime}. 066 * 067 * @param time UNIX timestamp (seconds). 068 * @return the corresponding FileTime. 069 * @since 2.16.0 070 */ 071 public static FileTime fromUnixTime(final long time) { 072 return FileTime.from(time, TimeUnit.SECONDS); 073 } 074 075 /** 076 * Tests whether a FileTime can be safely represented in the standard UNIX time. 077 * <p> 078 * If the FileTime is null, this method returns true. 079 * </p> 080 * 081 * @param time the FileTime to evaluate, can be null. 082 * @return true if the time exceeds the minimum or maximum UNIX time, false otherwise. 083 * @since 2.16.0 084 */ 085 public static boolean isUnixTime(final FileTime time) { 086 return isUnixTime(toUnixTime(time)); 087 } 088 089 /** 090 * Tests whether a given number of seconds (since Epoch) can be safely represented in the standard UNIX time. 091 * 092 * @param seconds the number of seconds (since Epoch) to evaluate. 093 * @return true if the time can be represented in the standard UNIX time, false otherwise. 094 * @since 2.16.0 095 */ 096 public static boolean isUnixTime(final long seconds) { 097 return Integer.MIN_VALUE <= seconds && seconds <= Integer.MAX_VALUE; 098 } 099 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}