Repository navigation
fs.statSync, fs.stat and fs.promises.stat returns 'Invalid Date' for atime/ctime/mtime with negative epoch time #43707
Copy link
Copy link
Closed
Labels
confirmed-bugIssues and PRs for confirmed bugs.Issues and PRs for confirmed bugs.fsIssues and PRs related to file-system APIs and the fs module.Issues and PRs related to file-system APIs and the fs module.
Description
Version
v16.15.1
Platform
Linux localhost.localdomain 4.18.0-394.el8.x86_64 #1 SMP Tue May 31 16:19:11 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Subsystem
File system
What steps will reproduce the bug?
- create a file with minus epoch time.
$ touch --date=@-1 hogehoge
$ ls --full-time hogehoge
-rw-rw-r--. 1 kusanagi kusanagi 0 1969-12-31 23:59:59.000000000 +0000 hogehoge- run the following code to test
fs.statSyncandfs.promises.statfor file hogehoge.
import { stat } from 'fs/promises';
import { statSync } from 'fs';
async function test() {
const stats = await stat('hogehoge');
console.log({stats});
console.log(stats.mtime);
console.log(stats.mtime.getTime());
}
function testSync() {
const stats = statSync('hogehoge');
console.log({stats});
console.log(stats.mtime);
console.log(stats.mtime.getTime());
}
await test();
testSync();{
stats: Stats {
dev: 64768,
mode: 33204,
nlink: 1,
uid: 1000,
gid: 1000,
rdev: 0,
blksize: 4096,
ino: 56395369,
size: 0,
blocks: 0,
atimeMs: 1.8446744073709552e+22,
mtimeMs: 1.8446744073709552e+22,
ctimeMs: 1657161984281.557,
birthtimeMs: 1657161921560.5312,
atime: Invalid Date,
mtime: Invalid Date,
ctime: 2022-07-07T02:46:24.282Z,
birthtime: 2022-07-07T02:45:21.561Z
}
}
Invalid Date
NaN
{
stats: Stats {
dev: 64768,
mode: 33204,
nlink: 1,
uid: 1000,
gid: 1000,
rdev: 0,
blksize: 4096,
ino: 56395369,
size: 0,
blocks: 0,
atimeMs: 1.8446744073709552e+22,
mtimeMs: 1.8446744073709552e+22,
ctimeMs: 1657161984281.557,
birthtimeMs: 1657161921560.5312,
atime: Invalid Date,
mtime: Invalid Date,
ctime: 2022-07-07T02:46:24.282Z,
birthtime: 2022-07-07T02:45:21.561Z
}
}
Invalid Date
NaNHow often does it reproduce? Is there a required condition?
Always.
What is the expected behavior?
ctime/mtime/atime with negative epoch time shall be treated as it is.
In other words, if -1 then it shall be 1 second before epoch.
Actually, Date() supports negative epoch time.
$ node
Welcome to Node.js v16.15.1.
Type ".help" for more information.
> new Date(-1)
1969-12-31T23:59:59.999Z
>As stat(2) supports negative epoch time, which can be observed via ls command, I don't see why fs.stat/fs.statSync/fs.promises.stat treats negative epoch as NaN.
What do you see instead?
$ touch --date=@-1 hogehoge
$ ls --full-time hogehoge
-rw-rw-r--. 1 kusanagi kusanagi 0 1969-12-31 23:59:59.000000000 +0000 hogehoge
$ cat > test.mjs
import { stat } from 'fs/promises';
import { statSync } from 'fs';
async function test() {
const stats = await stat('hogehoge');
console.log({stats});
console.log(stats.mtime);
console.log(stats.mtime.getTime());
}
function testSync() {
const stats = statSync('hogehoge');
console.log({stats});
console.log(stats.mtime);
console.log(stats.mtime.getTime());
}
await test();
testSync();
$ node test.mjs
{
stats: Stats {
dev: 64768,
mode: 33204,
nlink: 1,
uid: 1000,
gid: 1000,
rdev: 0,
blksize: 4096,
ino: 56395369,
size: 0,
blocks: 0,
atimeMs: 1.8446744073709552e+22,
mtimeMs: 1.8446744073709552e+22,
ctimeMs: 1657161984281.557,
birthtimeMs: 1657161921560.5312,
atime: Invalid Date,
mtime: Invalid Date,
ctime: 2022-07-07T02:46:24.282Z,
birthtime: 2022-07-07T02:45:21.561Z
}
}
Invalid Date
NaN
{
stats: Stats {
dev: 64768,
mode: 33204,
nlink: 1,
uid: 1000,
gid: 1000,
rdev: 0,
blksize: 4096,
ino: 56395369,
size: 0,
blocks: 0,
atimeMs: 1.8446744073709552e+22,
mtimeMs: 1.8446744073709552e+22,
ctimeMs: 1657161984281.557,
birthtimeMs: 1657161921560.5312,
atime: Invalid Date,
mtime: Invalid Date,
ctime: 2022-07-07T02:46:24.282Z,
birthtime: 2022-07-07T02:45:21.561Z
}
}
Invalid Date
NaNAdditional information
No response
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
confirmed-bugIssues and PRs for confirmed bugs.Issues and PRs for confirmed bugs.fsIssues and PRs related to file-system APIs and the fs module.Issues and PRs related to file-system APIs and the fs module.
Activity
targos commentedon Jul 7, 2022
@nodejs/fs
bnoordhuis commentedon Jul 7, 2022
It's a signed-to-unsigned conversion bug:
Internally, the stats are handed off from C++ to JS in a BigUint64Array but that makes negative values wrap around. The fix is to use a BigInt64Array instead. Pull request welcome.
edit: in particular, it's this (insidiously misnamed) field:
node/src/node_file.h
Line 21 in 7d13f5e
And here is where it's converted to a stats object:
node/lib/internal/fs/utils.js
Lines 534 to 545 in 7d13f5e
LiviaMedeiros commentedon Jul 7, 2022
Non-bigint stats are returned as
Float64Arrayso perhaps this requires adjustingunsigned long longs (or what it's aliased to) in C++ bindings as well.bnoordhuis commentedon Jul 7, 2022
Sorry yes, I forgot to mention that. That logic is here:
node/src/node_file-inl.h
Lines 93 to 95 in 7d13f5e
fs: use signed types for stat data
LiviaMedeiros commentedon Jul 18, 2022
Note: on Windows platform, there still is an overflow on negative dates, to postpone Y2038 overflow.
It shouldn't lead to
Invalid Date, and right now is unavoidable without breaking underlying ABI.fs: use signed types for stat data
fs: use signed types for stat data
girlfriendfletcher commentedon Oct 14, 2025
@LiviaMedeiros https://treacherylex.github.io/2gzu7uSJzYgn4NSrXqx6vOeaoaPwIOdxYI2RjPi0y_ZNSbr1lTsp/