Skip to content

Commit d88342b

Browse files
committed
fs: expose Stats times as Numbers
This also reverts commit 9836cf5. Fixes: npm/npm#16734 Ref: #12607 Ref: #12818
1 parent f84666f commit d88342b

File tree

3 files changed

+52
-115
lines changed

3 files changed

+52
-115
lines changed

doc/api/fs.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,14 @@ argument to `fs.createReadStream()`. If `path` is passed as a string, then
295295
## Class: fs.Stats
296296
<!-- YAML
297297
added: v0.1.21
298+
changes:
299+
- version: REPLACEME
300+
pr-url: https://github.com/nodejs/node/pull/13173
301+
description: Added times as numbers.
298302
-->
299303

300-
Objects returned from [`fs.stat()`][], [`fs.lstat()`][] and [`fs.fstat()`][] and their
301-
synchronous counterparts are of this type.
304+
Objects returned from [`fs.stat()`][], [`fs.lstat()`][] and [`fs.fstat()`][] and
305+
their synchronous counterparts are of this type.
302306

303307
- `stats.isFile()`
304308
- `stats.isDirectory()`
@@ -323,20 +327,22 @@ Stats {
323327
size: 527,
324328
blksize: 4096,
325329
blocks: 8,
330+
atimeMs: 1318289051000.1,
331+
mtimeMs: 1318289051000.1,
332+
ctimeMs: 1318289051000.1,
333+
birthtimeMs: 1318289051000.1,
326334
atime: Mon, 10 Oct 2011 23:24:11 GMT,
327335
mtime: Mon, 10 Oct 2011 23:24:11 GMT,
328336
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
329337
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
330338
```
331339

332-
Please note that `atime`, `mtime`, `birthtime`, and `ctime` are
333-
instances of [`Date`][MDN-Date] object and appropriate methods should be used
334-
to compare the values of these objects. For most general uses
335-
[`getTime()`][MDN-Date-getTime] will return the number of milliseconds elapsed
336-
since _1 January 1970 00:00:00 UTC_ and this integer should be sufficient for
337-
any comparison, however there are additional methods which can be used for
338-
displaying fuzzy information. More details can be found in the
339-
[MDN JavaScript Reference][MDN-Date] page.
340+
*Note*: `atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs` are [numbers][MDN-Number]
341+
that hold the corresponding times in milliseconds. Their precision is platform
342+
specific. `atime`, `mtime`, `ctime`, and `birthtime` are [`Date`][MDN-Date]
343+
object alternate representations of the various times. The `Date` and number
344+
values are not connected. Assigning a new number value, or mutating the `Date`
345+
value, will not be reflected in the corresponding alternate representation.
340346

341347
### Stat Time Values
342348

@@ -527,7 +533,7 @@ The "not recommended" examples above check for accessibility and then use the
527533
file; the "recommended" examples are better because they use the file directly
528534
and handle the error, if any.
529535

530-
In general, check for the accessibility of a file only if the file wont be
536+
In general, check for the accessibility of a file only if the file won't be
531537
used directly, for example when its accessibility is a signal from another
532538
process.
533539

@@ -959,7 +965,7 @@ The "not recommended" examples above check for existence and then use the
959965
file; the "recommended" examples are better because they use the file directly
960966
and handle the error, if any.
961967

962-
In general, check for the existence of a file only if the file wont be
968+
In general, check for the existence of a file only if the file won't be
963969
used directly, for example when its existence is a signal from another
964970
process.
965971

lib/fs.js

Lines changed: 8 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -196,81 +196,17 @@ function Stats(
196196
this.ino = ino;
197197
this.size = size;
198198
this.blocks = blocks;
199-
this._atim_msec = atim_msec;
200-
this._mtim_msec = mtim_msec;
201-
this._ctim_msec = ctim_msec;
202-
this._birthtim_msec = birthtim_msec;
199+
this.atimeMs = atim_msec;
200+
this.mtimeMs = mtim_msec;
201+
this.ctimeMs = ctim_msec;
202+
this.birthtimeMs = birthtim_msec;
203+
this.atime = new Date(atim_msec);
204+
this.mtime = new Date(mtim_msec);
205+
this.ctime = new Date(ctim_msec);
206+
this.birthtime = new Date(birthtim_msec);
203207
}
204208
fs.Stats = Stats;
205209

206-
// defining the properties in this fashion (explicitly with no loop or factory)
207-
// has been shown to be the most performant on V8 contemp.
208-
// Ref: https://github.com/nodejs/node/pull/12818
209-
// + 0.5 is added to the Dates to protect values from being rounded down
210-
// Ref: https://github.com/nodejs/node/pull/12607
211-
Object.defineProperties(Stats.prototype, {
212-
atime: {
213-
configurable: true,
214-
enumerable: true,
215-
get() {
216-
return this._atime !== undefined ?
217-
this._atime :
218-
(this._atime = new Date(this._atim_msec + 0.5));
219-
},
220-
set(value) { return this._atime = value; }
221-
},
222-
mtime: {
223-
configurable: true,
224-
enumerable: true,
225-
get() {
226-
return this._mtime !== undefined ?
227-
this._mtime :
228-
(this._mtime = new Date(this._mtim_msec + 0.5));
229-
},
230-
set(value) { return this._mtime = value; }
231-
},
232-
ctime: {
233-
configurable: true,
234-
enumerable: true,
235-
get() {
236-
return this._ctime !== undefined ?
237-
this._ctime :
238-
(this._ctime = new Date(this._ctim_msec + 0.5));
239-
},
240-
set(value) { return this._ctime = value; }
241-
},
242-
birthtime: {
243-
configurable: true,
244-
enumerable: true,
245-
get() {
246-
return this._birthtime !== undefined ?
247-
this._birthtime :
248-
(this._birthtime = new Date(this._birthtim_msec + 0.5));
249-
},
250-
set(value) { return this._birthtime = value; }
251-
},
252-
});
253-
254-
Stats.prototype.toJSON = function toJSON() {
255-
return {
256-
dev: this.dev,
257-
mode: this.mode,
258-
nlink: this.nlink,
259-
uid: this.uid,
260-
gid: this.gid,
261-
rdev: this.rdev,
262-
blksize: this.blksize,
263-
ino: this.ino,
264-
size: this.size,
265-
blocks: this.blocks,
266-
atime: this.atime,
267-
ctime: this.ctime,
268-
mtime: this.mtime,
269-
birthtime: this.birthtime
270-
};
271-
};
272-
273-
274210
Stats.prototype._checkModeProperty = function(property) {
275211
return ((this.mode & S_IFMT) === property);
276212
};

test/parallel/test-fs-stat.js

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -65,60 +65,55 @@ fs.open('.', 'r', undefined, common.mustCall(function(err, fd) {
6565
assert.fail(err);
6666
}
6767
if (stats) {
68-
console.dir(stats);
6968
assert.ok(stats.mtime instanceof Date);
7069
}
7170
fs.close(fd, assert.ifError);
7271
}));
7372

74-
console.log(`stating: ${__filename}`);
7573
fs.stat(__filename, common.mustCall(function(err, s) {
7674
assert.ifError(err);
77-
78-
console.dir(s);
79-
80-
console.log(`isDirectory: ${JSON.stringify(s.isDirectory())}`);
8175
assert.strictEqual(false, s.isDirectory());
82-
83-
console.log(`isFile: ${JSON.stringify(s.isFile())}`);
8476
assert.strictEqual(true, s.isFile());
85-
86-
console.log(`isSocket: ${JSON.stringify(s.isSocket())}`);
8777
assert.strictEqual(false, s.isSocket());
88-
89-
console.log(`isBlockDevice: ${JSON.stringify(s.isBlockDevice())}`);
9078
assert.strictEqual(false, s.isBlockDevice());
91-
92-
console.log(`isCharacterDevice: ${JSON.stringify(s.isCharacterDevice())}`);
9379
assert.strictEqual(false, s.isCharacterDevice());
94-
95-
console.log(`isFIFO: ${JSON.stringify(s.isFIFO())}`);
9680
assert.strictEqual(false, s.isFIFO());
97-
98-
console.log(`isSymbolicLink: ${JSON.stringify(s.isSymbolicLink())}`);
9981
assert.strictEqual(false, s.isSymbolicLink());
100-
101-
assert.ok(s.atime instanceof Date);
102-
assert.ok(s.mtime instanceof Date);
103-
assert.ok(s.ctime instanceof Date);
104-
assert.ok(s.birthtime instanceof Date);
105-
}));
106-
107-
fs.stat(__filename, common.mustCall(function(err, s) {
108-
const json = JSON.parse(JSON.stringify(s));
10982
const keys = [
11083
'dev', 'mode', 'nlink', 'uid',
111-
'gid', 'rdev', 'ino',
112-
'size', 'atime', 'mtime',
113-
'ctime', 'birthtime'
84+
'gid', 'rdev', 'ino', 'size',
85+
'atimeMs', 'mtimeMs', 'ctimeMs', 'birthtimeMs',
86+
'atime', 'mtime', 'ctime', 'birthtime'
87+
];
88+
const dateFields = [ 'atime', 'mtime', 'ctime', 'birthtime' ];
89+
const numberFields = [
90+
'dev', 'mode', 'nlink', 'uid', 'gid', 'rdev', 'ino', 'size',
91+
'atimeMs', 'mtimeMs', 'ctimeMs', 'birthtimeMs'
11492
];
11593
if (!common.isWindows) {
11694
keys.push('blocks', 'blksize');
95+
numberFields.push('blocks', 'blksize');
11796
}
97+
const actualKeys = Object.keys(s);
98+
keys.forEach((k) => assert.strictEqual(actualKeys.includes(k), true,
99+
`${k} should a field of s`));
100+
numberFields.forEach((k) => {
101+
assert.strictEqual(typeof s[k], 'number', `${k} should be a number`);
102+
});
103+
dateFields.forEach((k) => {
104+
assert.ok(s[k] instanceof Date, `${k} should be a Date`);
105+
});
106+
const parsed = JSON.parse(JSON.stringify(s));
118107
keys.forEach(function(k) {
119108
assert.ok(
120-
json[k] !== undefined && json[k] !== null,
109+
parsed[k] !== undefined && parsed[k] !== null,
121110
k + ' should not be null or undefined'
122111
);
123112
});
113+
numberFields.forEach((k) => {
114+
assert.strictEqual(typeof parsed[k], 'number', `${k} should be a number`);
115+
});
116+
dateFields.forEach((k) => {
117+
assert.strictEqual(typeof parsed[k], 'string', `${k} should be a string`);
118+
});
124119
}));

0 commit comments

Comments
 (0)