forked from pranjalbajaj/java7-sourcecode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileTime.java
More file actions
363 lines (333 loc) · 12 KB
/
Copy pathFileTime.java
File metadata and controls
363 lines (333 loc) · 12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.nio.file.attribute;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
/**
* Represents the value of a file's time stamp attribute. For example, it may
* represent the time that the file was last
* {@link BasicFileAttributes#lastModifiedTime() modified},
* {@link BasicFileAttributes#lastAccessTime() accessed},
* or {@link BasicFileAttributes#creationTime() created}.
*
* <p> Instances of this class are immutable.
*
* @since 1.7
* @see java.nio.file.Files#setLastModifiedTime
* @see java.nio.file.Files#getLastModifiedTime
*/
public final class FileTime
implements Comparable<FileTime>
{
/**
* The value since the epoch; can be negative.
*/
private final long value;
/**
* The unit of granularity to interpret the value.
*/
private final TimeUnit unit;
/**
* The value return by toString (created lazily)
*/
private String valueAsString;
/**
* The value in days and excess nanos (created lazily)
*/
private DaysAndNanos daysAndNanos;
/**
* Returns a DaysAndNanos object representing the value.
*/
private DaysAndNanos asDaysAndNanos() {
if (daysAndNanos == null)
daysAndNanos = new DaysAndNanos(value, unit);
return daysAndNanos;
}
/**
* Initializes a new instance of this class.
*/
private FileTime(long value, TimeUnit unit) {
if (unit == null)
throw new NullPointerException();
this.value = value;
this.unit = unit;
}
/**
* Returns a {@code FileTime} representing a value at the given unit of
* granularity.
*
* @param value
* the value since the epoch (1970-01-01T00:00:00Z); can be
* negative
* @param unit
* the unit of granularity to interpret the value
*
* @return a {@code FileTime} representing the given value
*/
public static FileTime from(long value, TimeUnit unit) {
return new FileTime(value, unit);
}
/**
* Returns a {@code FileTime} representing the given value in milliseconds.
*
* @param value
* the value, in milliseconds, since the epoch
* (1970-01-01T00:00:00Z); can be negative
*
* @return a {@code FileTime} representing the given value
*/
public static FileTime fromMillis(long value) {
return new FileTime(value, TimeUnit.MILLISECONDS);
}
/**
* Returns the value at the given unit of granularity.
*
* <p> Conversion from a coarser granularity that would numerically overflow
* saturate to {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE}
* if positive.
*
* @param unit
* the unit of granularity for the return value
*
* @return value in the given unit of granularity, since the epoch
* since the epoch (1970-01-01T00:00:00Z); can be negative
*/
public long to(TimeUnit unit) {
return unit.convert(this.value, this.unit);
}
/**
* Returns the value in milliseconds.
*
* <p> Conversion from a coarser granularity that would numerically overflow
* saturate to {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE}
* if positive.
*
* @return the value in milliseconds, since the epoch (1970-01-01T00:00:00Z)
*/
public long toMillis() {
return unit.toMillis(value);
}
/**
* Tests this {@code FileTime} for equality with the given object.
*
* <p> The result is {@code true} if and only if the argument is not {@code
* null} and is a {@code FileTime} that represents the same time. This
* method satisfies the general contract of the {@code Object.equals} method.
*
* @param obj
* the object to compare with
*
* @return {@code true} if, and only if, the given object is a {@code
* FileTime} that represents the same time
*/
@Override
public boolean equals(Object obj) {
return (obj instanceof FileTime) ? compareTo((FileTime)obj) == 0 : false;
}
/**
* Computes a hash code for this file time.
*
* <p> The hash code is based upon the value represented, and satisfies the
* general contract of the {@link Object#hashCode} method.
*
* @return the hash-code value
*/
@Override
public int hashCode() {
// hashcode of days/nanos representation to satisfy contract with equals
return asDaysAndNanos().hashCode();
}
/**
* Compares the value of two {@code FileTime} objects for order.
*
* @param other
* the other {@code FileTime} to be compared
*
* @return {@code 0} if this {@code FileTime} is equal to {@code other}, a
* value less than 0 if this {@code FileTime} represents a time
* that is before {@code other}, and a value greater than 0 if this
* {@code FileTime} represents a time that is after {@code other}
*/
@Override
public int compareTo(FileTime other) {
// same granularity
if (unit == other.unit) {
return (value < other.value) ? -1 : (value == other.value ? 0 : 1);
} else {
// compare using days/nanos representation when unit differs
return asDaysAndNanos().compareTo(other.asDaysAndNanos());
}
}
/**
* Returns the string representation of this {@code FileTime}. The string
* is returned in the <a
* href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> format:
* <pre>
* YYYY-MM-DDThh:mm:ss[.s+]Z
* </pre>
* where "{@code [.s+]}" represents a dot followed by one of more digits
* for the decimal fraction of a second. It is only present when the decimal
* fraction of a second is not zero. For example, {@code
* FileTime.fromMillis(1234567890000L).toString()} yields {@code
* "2009-02-13T23:31:30Z"}, and {@code FileTime.fromMillis(1234567890123L).toString()}
* yields {@code "2009-02-13T23:31:30.123Z"}.
*
* <p> A {@code FileTime} is primarily intended to represent the value of a
* file's time stamp. Where used to represent <i>extreme values</i>, where
* the year is less than "{@code 0001}" or greater than "{@code 9999}" then
* this method deviates from ISO 8601 in the same manner as the
* <a href="http://www.w3.org/TR/xmlschema-2/#deviantformats">XML Schema
* language</a>. That is, the year may be expanded to more than four digits
* and may be negative-signed. If more than four digits then leading zeros
* are not present. The year before "{@code 0001}" is "{@code -0001}".
*
* @return the string representation of this file time
*/
@Override
public String toString() {
String v = valueAsString;
if (v == null) {
// overflow saturates to Long.MIN_VALUE or Long.MAX_VALUE so this
// limits the range:
// [-292275056-05-16T16:47:04.192Z,292278994-08-17T07:12:55.807Z]
long ms = toMillis();
// nothing to do when seconds/minutes/hours/days
String fractionAsString = "";
if (unit.compareTo(TimeUnit.SECONDS) < 0) {
long fraction = asDaysAndNanos().fractionOfSecondInNanos();
if (fraction != 0L) {
// fraction must be positive
if (fraction < 0L) {
final long MAX_FRACTION_PLUS_1 = 1000L * 1000L * 1000L;
fraction += MAX_FRACTION_PLUS_1;
if (ms != Long.MIN_VALUE) ms--;
}
// convert to String, adding leading zeros as required and
// stripping any trailing zeros
String s = Long.toString(fraction);
int len = s.length();
int width = 9 - len;
StringBuilder sb = new StringBuilder(".");
while (width-- > 0) {
sb.append('0');
}
if (s.charAt(len-1) == '0') {
// drop trailing zeros
len--;
while (s.charAt(len-1) == '0')
len--;
sb.append(s.substring(0, len));
} else {
sb.append(s);
}
fractionAsString = sb.toString();
}
}
// create calendar to use with formatter.
GregorianCalendar cal =
new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
if (value < 0L)
cal.setGregorianChange(new Date(Long.MIN_VALUE));
cal.setTimeInMillis(ms);
// years are negative before common era
String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : "";
// [-]YYYY-MM-DDThh:mm:ss[.s]Z
v = new Formatter(Locale.ROOT)
.format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString)
.toString();
valueAsString = v;
}
return v;
}
/**
* Represents a FileTime's value as two longs: the number of days since
* the epoch, and the excess (in nanoseconds). This is used for comparing
* values with different units of granularity.
*/
private static class DaysAndNanos implements Comparable<DaysAndNanos> {
// constants for conversion
private static final long C0 = 1L;
private static final long C1 = C0 * 24L;
private static final long C2 = C1 * 60L;
private static final long C3 = C2 * 60L;
private static final long C4 = C3 * 1000L;
private static final long C5 = C4 * 1000L;
private static final long C6 = C5 * 1000L;
/**
* The value (in days) since the epoch; can be negative.
*/
private final long days;
/**
* The excess (in nanoseconds); can be negative if days <= 0.
*/
private final long excessNanos;
/**
* Initializes a new instance of this class.
*/
DaysAndNanos(long value, TimeUnit unit) {
long scale;
switch (unit) {
case DAYS : scale = C0; break;
case HOURS : scale = C1; break;
case MINUTES : scale = C2; break;
case SECONDS : scale = C3; break;
case MILLISECONDS : scale = C4; break;
case MICROSECONDS : scale = C5; break;
case NANOSECONDS : scale = C6; break;
default : throw new AssertionError("Unit not handled");
}
this.days = unit.toDays(value);
this.excessNanos = unit.toNanos(value - (this.days * scale));
}
/**
* Returns the fraction of a second, in nanoseconds.
*/
long fractionOfSecondInNanos() {
return excessNanos % (1000L * 1000L * 1000L);
}
@Override
public boolean equals(Object obj) {
return (obj instanceof DaysAndNanos) ?
compareTo((DaysAndNanos)obj) == 0 : false;
}
@Override
public int hashCode() {
return (int)(days ^ (days >>> 32) ^
excessNanos ^ (excessNanos >>> 32));
}
@Override
public int compareTo(DaysAndNanos other) {
if (this.days != other.days)
return (this.days < other.days) ? -1 : 1;
return (this.excessNanos < other.excessNanos) ? -1 :
(this.excessNanos == other.excessNanos) ? 0 : 1;
}
}
}