src/share/classes/java/nio/file/attribute/FileTime.java

Print this page




  24  */
  25 
  26 package java.nio.file.attribute;
  27 
  28 import java.util.Calendar;
  29 import java.util.GregorianCalendar;
  30 import java.util.Date;
  31 import java.util.Formatter;
  32 import java.util.Locale;
  33 import java.util.TimeZone;
  34 import java.util.concurrent.TimeUnit;
  35 
  36 /**
  37  * Represents the value of a file's time stamp attribute. For example, it may
  38  * represent the time that the file was last modified, accessed, or created.
  39  *
  40  * <p> Instances of this class are immutable.
  41  *
  42  * @since 1.7
  43  * @see BasicFileAttributes
  44  * @see Attributes#setLastModifiedTime
  45  */
  46 
  47 public final class FileTime implements Comparable<FileTime> {





  48     private final long value;




  49     private final TimeUnit unit;
  50     private String valueAsString;  // created lazily
  51 






















  52     private FileTime(long value, TimeUnit unit) {
  53         if (unit == null)
  54             throw new NullPointerException();
  55         this.value = value;
  56         this.unit = unit;
  57     }
  58 
  59     /**
  60      * Returns a {@code FileTime} representing a value at the given unit of
  61      * granularity.
  62      *
  63      * @param   value
  64      *          the value since the epoch (1970-01-01T00:00:00Z); can be
  65      *          negative
  66      * @param   unit
  67      *          the unit of granularity to interpret the value
  68      *
  69      * @return  a {@code FileTime} representing the given value
  70      */
  71     public static FileTime from(long value, TimeUnit unit) {


 126      *          the object to compare with
 127      *
 128      * @return  {@code true} if, and only if, the given object is a {@code
 129      *          FileTime} that represents the same time
 130      */
 131     @Override
 132     public boolean equals(Object obj) {
 133         return (obj instanceof FileTime) ? compareTo((FileTime)obj) == 0 : false;
 134     }
 135 
 136     /**
 137      * Computes a hash code for this file time.
 138      *
 139      * <p> The hash code is based upon the value represented, and satisfies the
 140      * general contract of the {@link Object#hashCode} method.
 141      *
 142      * @return  the hash-code value
 143      */
 144     @Override
 145     public int hashCode() {
 146         // hash value for fixed granularity to satisfy contract with equals
 147         long ms = toMillis();
 148         return (int)(ms ^ (ms >>> 32));
 149     }
 150 
 151     /**
 152      * Compares the value of two {@code FileTime} objects for order.
 153      *
 154      * @param   other
 155      *          the other {@code FileTime} to be compared
 156      *
 157      * @return  {@code 0} if this {@code FileTime} is equal to {@code other}, a
 158      *          value less than 0 if this {@code FileTime} represents a time
 159      *          that is before {@code other}, and a value greater than 0 if this
 160      *          {@code FileTime} represents a time that is after {@code other}
 161      */
 162     @Override
 163     public int compareTo(FileTime other) {
 164         // same granularity
 165         if (unit == other.unit)
 166             return (value < other.value) ? -1 : (value == other.value ? 0 : 1);
 167 
 168         // compare in days
 169         long thisValueInDays = unit.toDays(value);
 170         long otherValueInDays = other.unit.toDays(other.value);
 171         if (thisValueInDays != otherValueInDays)
 172             return (thisValueInDays < otherValueInDays) ? -1 : 1;
 173 
 174         // compare remainder in nanoseconds
 175         long thisRemainder = remainderInNanos(thisValueInDays);
 176         long otherRemainder = other.remainderInNanos(otherValueInDays);
 177         return (thisRemainder < otherRemainder) ? -1 :
 178             (thisRemainder == otherRemainder) ? 0 : 1;
 179     }
 180 
 181     private long remainderInNanos(long days) {
 182         // constants for conversion
 183         final long C0 = 1L;
 184         final long C1 = C0 * 24L;
 185         final long C2 = C1 * 60L;
 186         final long C3 = C2 * 60L;
 187         final long C4 = C3 * 1000L;
 188         final long C5 = C4 * 1000L;
 189         final long C6 = C5 * 1000L;
 190 
 191         long scale;
 192         switch (unit) {
 193             case DAYS         : scale = C0; break;
 194             case HOURS        : scale = C1; break;
 195             case MINUTES      : scale = C2; break;
 196             case SECONDS      : scale = C3; break;
 197             case MILLISECONDS : scale = C4; break;
 198             case MICROSECONDS : scale = C5; break;
 199             case NANOSECONDS  : scale = C6; break;
 200             default:
 201                 throw new AssertionError("Unit not handled");
 202         }
 203         long rem = value - (days * scale);
 204         return unit.toNanos(rem);
 205     }
 206 
 207     /**
 208      * Returns the string representation of this {@code FileTime}. The string
 209      * is returned in the <a
 210      * href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a> format:
 211      * <pre>
 212      *     YYYY-MM-DDThh:mm:ss[.s+]Z
 213      * </pre>
 214      * where "{@code [.s+]}" represents a dot followed by one of more digits
 215      * for the decimal fraction of a second. It is only present when the decimal
 216      * fraction of a second is not zero. For example, {@code
 217      * FileTime.fromMillis(1234567890000L).toString()} yields {@code
 218      * "2009-02-13T23:31:30Z"}, and {@code FileTime.fromMillis(1234567890123L).toString()}
 219      * yields {@code "2009-02-13T23:31:30.123Z"}.
 220      *
 221      * <p> A {@code FileTime} is primarly intended to represent the value of a
 222      * file's time stamp. Where used to represent <i>extreme values</i>, where
 223      * the year is less than "{@code 0001}" or greater than "{@code 9999}" then
 224      * the year may be expanded to more than four digits and may be
 225      * negative-signed. If more than four digits then leading zeros are not
 226      * present. The year before "{@code 0001}" is "{@code -0001}".
 227      *
 228      * @return  the string representation of this file time
 229      */
 230     @Override
 231     public String toString() {
 232         String v = valueAsString;
 233         if (v == null) {
 234             // overflow saturates to Long.MIN_VALUE or Long.MAX_VALUE so this
 235             // limits the range:
 236             // [-292275056-05-16T16:47:04.192Z,292278994-08-17T07:12:55.807Z]
 237             long ms = toMillis();
 238 
 239             // nothing to do when seconds/minutes/hours/days
 240             String fractionAsString = "";
 241             if (unit.compareTo(TimeUnit.SECONDS) < 0) {
 242                 // constants for conversion
 243                 final long C0 = 1L;
 244                 final long C1 = C0 * 1000L;
 245                 final long C2 = C1 * 1000L;
 246                 final long C3 = C2 * 1000L;
 247 
 248                 long scale;
 249                 int width;
 250                 switch (unit) {
 251                     case MILLISECONDS : scale = C1; width = 3; break;
 252                     case MICROSECONDS : scale = C2; width = 6; break;
 253                     case NANOSECONDS  : scale = C3; width = 9; break;
 254                     default:
 255                         throw new AssertionError("Unit not handled");
 256                 }
 257                 long fraction = value % scale;
 258                 if (fraction != 0L) {
 259                     // fraction must be positive
 260                     if (fraction < 0L) {
 261                         fraction += scale;

 262                         if (ms != Long.MIN_VALUE) ms--;
 263                     }
 264 
 265                     // convert to String, adding leading zeros as required and
 266                     // stripping any trailing zeros
 267                     String s = Long.toString(fraction);
 268                     int len = s.length();
 269                     width -= len;
 270                     StringBuilder sb = new StringBuilder(".");
 271                     while (width-- > 0) {
 272                         sb.append('0');
 273                     }
 274                     if (s.charAt(len-1) == '0') {
 275                         // drop trailing zeros
 276                         len--;
 277                         while (s.charAt(len-1) == '0')
 278                             len--;
 279                         sb.append(s.substring(0, len));
 280                     } else {
 281                         sb.append(s);
 282                     }
 283                     fractionAsString = sb.toString();
 284                 }
 285             }
 286 
 287             // create calendar to use with formatter.
 288             GregorianCalendar cal =
 289                 new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
 290             if (value < 0L)
 291                 cal.setGregorianChange(new Date(Long.MIN_VALUE));
 292             cal.setTimeInMillis(ms);
 293 
 294             // years are negative before common era
 295             String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : "";
 296 
 297             // [-]YYYY-MM-DDThh:mm:ss[.s]Z
 298             v = new Formatter(Locale.ROOT)
 299                 .format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString)
 300                 .toString();
 301             valueAsString = v;
 302         }
 303         return v;
 304     }








































































 305 }


  24  */
  25 
  26 package java.nio.file.attribute;
  27 
  28 import java.util.Calendar;
  29 import java.util.GregorianCalendar;
  30 import java.util.Date;
  31 import java.util.Formatter;
  32 import java.util.Locale;
  33 import java.util.TimeZone;
  34 import java.util.concurrent.TimeUnit;
  35 
  36 /**
  37  * Represents the value of a file's time stamp attribute. For example, it may
  38  * represent the time that the file was last modified, accessed, or created.
  39  *
  40  * <p> Instances of this class are immutable.
  41  *
  42  * @since 1.7
  43  * @see BasicFileAttributes

  44  */
  45 
  46 public final class FileTime
  47     implements Comparable<FileTime>
  48 {
  49     /**
  50      * The value since the epoch; can be negative.
  51      */
  52     private final long value;
  53 
  54     /**
  55      * The unit of granularity to interpret the value.
  56      */
  57     private final TimeUnit unit;

  58 
  59     /**
  60      * The value return by toString (created lazily)
  61      */
  62     private String valueAsString;
  63 
  64     /**
  65      * The value in days and excess nanos (created lazily)
  66      */
  67     private DaysAndNanos daysAndNanos;
  68 
  69     /**
  70      * Returns a DaysAndNanos object representing the value.
  71      */
  72     private DaysAndNanos asDaysAndNanos() {
  73         if (daysAndNanos == null)
  74             daysAndNanos = new DaysAndNanos(value, unit);
  75         return daysAndNanos;
  76     }
  77 
  78     /**
  79      * Initializes a new instance of this class.
  80      */
  81     private FileTime(long value, TimeUnit unit) {
  82         if (unit == null)
  83             throw new NullPointerException();
  84         this.value = value;
  85         this.unit = unit;
  86     }
  87 
  88     /**
  89      * Returns a {@code FileTime} representing a value at the given unit of
  90      * granularity.
  91      *
  92      * @param   value
  93      *          the value since the epoch (1970-01-01T00:00:00Z); can be
  94      *          negative
  95      * @param   unit
  96      *          the unit of granularity to interpret the value
  97      *
  98      * @return  a {@code FileTime} representing the given value
  99      */
 100     public static FileTime from(long value, TimeUnit unit) {


 155      *          the object to compare with
 156      *
 157      * @return  {@code true} if, and only if, the given object is a {@code
 158      *          FileTime} that represents the same time
 159      */
 160     @Override
 161     public boolean equals(Object obj) {
 162         return (obj instanceof FileTime) ? compareTo((FileTime)obj) == 0 : false;
 163     }
 164 
 165     /**
 166      * Computes a hash code for this file time.
 167      *
 168      * <p> The hash code is based upon the value represented, and satisfies the
 169      * general contract of the {@link Object#hashCode} method.
 170      *
 171      * @return  the hash-code value
 172      */
 173     @Override
 174     public int hashCode() {
 175         // hashcode of days/nanos representation to satisfy contract with equals
 176         return asDaysAndNanos().hashCode();

 177     }
 178 
 179     /**
 180      * Compares the value of two {@code FileTime} objects for order.
 181      *
 182      * @param   other
 183      *          the other {@code FileTime} to be compared
 184      *
 185      * @return  {@code 0} if this {@code FileTime} is equal to {@code other}, a
 186      *          value less than 0 if this {@code FileTime} represents a time
 187      *          that is before {@code other}, and a value greater than 0 if this
 188      *          {@code FileTime} represents a time that is after {@code other}
 189      */
 190     @Override
 191     public int compareTo(FileTime other) {
 192         // same granularity
 193         if (unit == other.unit) {
 194             return (value < other.value) ? -1 : (value == other.value ? 0 : 1);
 195         } else {
 196             // compare using days/nanos representation when unit differs
 197             return asDaysAndNanos().compareTo(other.asDaysAndNanos());









 198         }






















 199     }



 200 
 201     /**
 202      * Returns the string representation of this {@code FileTime}. The string
 203      * is returned in the <a
 204      * href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a> format:
 205      * <pre>
 206      *     YYYY-MM-DDThh:mm:ss[.s+]Z
 207      * </pre>
 208      * where "{@code [.s+]}" represents a dot followed by one of more digits
 209      * for the decimal fraction of a second. It is only present when the decimal
 210      * fraction of a second is not zero. For example, {@code
 211      * FileTime.fromMillis(1234567890000L).toString()} yields {@code
 212      * "2009-02-13T23:31:30Z"}, and {@code FileTime.fromMillis(1234567890123L).toString()}
 213      * yields {@code "2009-02-13T23:31:30.123Z"}.
 214      *
 215      * <p> A {@code FileTime} is primarly intended to represent the value of a
 216      * file's time stamp. Where used to represent <i>extreme values</i>, where
 217      * the year is less than "{@code 0001}" or greater than "{@code 9999}" then
 218      * the year may be expanded to more than four digits and may be
 219      * negative-signed. If more than four digits then leading zeros are not
 220      * present. The year before "{@code 0001}" is "{@code -0001}".
 221      *
 222      * @return  the string representation of this file time
 223      */
 224     @Override
 225     public String toString() {
 226         String v = valueAsString;
 227         if (v == null) {
 228             // overflow saturates to Long.MIN_VALUE or Long.MAX_VALUE so this
 229             // limits the range:
 230             // [-292275056-05-16T16:47:04.192Z,292278994-08-17T07:12:55.807Z]
 231             long ms = toMillis();
 232 
 233             // nothing to do when seconds/minutes/hours/days
 234             String fractionAsString = "";
 235             if (unit.compareTo(TimeUnit.SECONDS) < 0) {
 236                 long fraction = asDaysAndNanos().fractionOfSecondInNanos();















 237                 if (fraction != 0L) {
 238                     // fraction must be positive
 239                     if (fraction < 0L) {
 240                         final long MAX_FRACTION_PLUS_1 = 1000L * 1000L * 1000L;
 241                         fraction += MAX_FRACTION_PLUS_1;
 242                         if (ms != Long.MIN_VALUE) ms--;
 243                     }
 244 
 245                     // convert to String, adding leading zeros as required and
 246                     // stripping any trailing zeros
 247                     String s = Long.toString(fraction);
 248                     int len = s.length();
 249                     int width = 9 - len;
 250                     StringBuilder sb = new StringBuilder(".");
 251                     while (width-- > 0) {
 252                         sb.append('0');
 253                     }
 254                     if (s.charAt(len-1) == '0') {
 255                         // drop trailing zeros
 256                         len--;
 257                         while (s.charAt(len-1) == '0')
 258                             len--;
 259                         sb.append(s.substring(0, len));
 260                     } else {
 261                         sb.append(s);
 262                     }
 263                     fractionAsString = sb.toString();
 264                 }
 265             }
 266 
 267             // create calendar to use with formatter.
 268             GregorianCalendar cal =
 269                 new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
 270             if (value < 0L)
 271                 cal.setGregorianChange(new Date(Long.MIN_VALUE));
 272             cal.setTimeInMillis(ms);
 273 
 274             // years are negative before common era
 275             String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : "";
 276 
 277             // [-]YYYY-MM-DDThh:mm:ss[.s]Z
 278             v = new Formatter(Locale.ROOT)
 279                 .format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString)
 280                 .toString();
 281             valueAsString = v;
 282         }
 283         return v;
 284     }
 285 
 286     /**
 287      * Represents a FileTime's value as two longs: the number of days since
 288      * the epoch, and the excess (in nanoseconds). This is used for comparing
 289      * values with different units of granularity.
 290      */
 291     private static class DaysAndNanos implements Comparable<DaysAndNanos> {
 292         // constants for conversion
 293         private static final long C0 = 1L;
 294         private static final long C1 = C0 * 24L;
 295         private static final long C2 = C1 * 60L;
 296         private static final long C3 = C2 * 60L;
 297         private static final long C4 = C3 * 1000L;
 298         private static final long C5 = C4 * 1000L;
 299         private static final long C6 = C5 * 1000L;
 300 
 301         /**
 302          * The value (in days) since the epoch; can be negative.
 303          */
 304         private final long days;
 305 
 306         /**
 307          * The excess (in nanoseconds); can be negative if days <= 0.
 308          */
 309         private final long excessNanos;
 310 
 311         /**
 312          * Initializes a new instance of this class.
 313          */
 314         DaysAndNanos(long value, TimeUnit unit) {
 315             long scale;
 316             switch (unit) {
 317                 case DAYS         : scale = C0; break;
 318                 case HOURS        : scale = C1; break;
 319                 case MINUTES      : scale = C2; break;
 320                 case SECONDS      : scale = C3; break;
 321                 case MILLISECONDS : scale = C4; break;
 322                 case MICROSECONDS : scale = C5; break;
 323                 case NANOSECONDS  : scale = C6; break;
 324                 default : throw new AssertionError("Unit not handled");
 325             }
 326             this.days = unit.toDays(value);
 327             this.excessNanos = unit.toNanos(value - (this.days * scale));
 328         }
 329 
 330         /**
 331          * Returns the fraction of a second, in nanoseconds.
 332          */
 333         long fractionOfSecondInNanos() {
 334             return excessNanos % (1000L * 1000L * 1000L);
 335         }
 336 
 337         @Override
 338         public boolean equals(Object obj) {
 339             return (obj instanceof DaysAndNanos) ?
 340                 compareTo((DaysAndNanos)obj) == 0 : false;
 341         }
 342 
 343         @Override
 344         public int hashCode() {
 345             return (int)(days ^ (days >>> 32) ^
 346                          excessNanos ^ (excessNanos >>> 32));
 347         }
 348 
 349         @Override
 350         public int compareTo(DaysAndNanos other) {
 351             if (this.days != other.days)
 352                 return (this.days < other.days) ? -1 : 1;
 353             return (this.excessNanos < other.excessNanos) ? -1 :
 354                    (this.excessNanos == other.excessNanos) ? 0 : 1;
 355         }
 356     }
 357 }