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 * Subtracts milliseconds from a source FileTime. 066 * 067 * @param fileTime The source FileTime. 068 * @param millisToSubtract The milliseconds to subtract. 069 * @return The resulting FileTime. 070 */ 071 public static FileTime minusMillis(final FileTime fileTime, final long millisToSubtract) { 072 return FileTime.from(fileTime.toInstant().minusMillis(millisToSubtract)); 073 } 074 075 /** 076 * Subtracts nanoseconds from a source FileTime. 077 * 078 * @param fileTime The source FileTime. 079 * @param nanosToSubtract The nanoseconds to subtract. 080 * @return The resulting FileTime. 081 */ 082 public static FileTime minusNanos(final FileTime fileTime, final long nanosToSubtract) { 083 return FileTime.from(fileTime.toInstant().minusNanos(nanosToSubtract)); 084 } 085 086 /** 087 * Subtracts seconds from a source FileTime. 088 * 089 * @param fileTime The source FileTime. 090 * @param secondsToSubtract The seconds to subtract. 091 * @return The resulting FileTime. 092 */ 093 public static FileTime minusSeconds(final FileTime fileTime, final long secondsToSubtract) { 094 return FileTime.from(fileTime.toInstant().minusSeconds(secondsToSubtract)); 095 } 096 097 /** 098 * Obtains the current instant FileTime from the system clock. 099 * 100 * @return the current instant FileTime from the system clock. 101 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 223 private FileTimes() { 224 // No instances. 225 } 226}