Skip to content

Commit 4ee7567

Browse files
fs: add Temporal.Instant support to Stats and BigIntStats
Signed-off-by: LiviaMedeiros <livia@cirno.name> PR-URL: #60789 Refs: #57891 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
1 parent 155268f commit 4ee7567

6 files changed

Lines changed: 304 additions & 19 deletions

File tree

doc/api/errors.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,6 +2465,18 @@ OpenSSL crypto support.
24652465
An attempt was made to use features that require [ICU][], but Node.js was not
24662466
compiled with ICU support.
24672467

2468+
<a id="ERR_NO_TEMPORAL"></a>
2469+
2470+
### `ERR_NO_TEMPORAL`
2471+
2472+
<!-- YAML
2473+
added: REPLACEME
2474+
-->
2475+
2476+
An attempt was made to use features that require [`Temporal`][], but Node.js was not
2477+
compiled with `Temporal` support or it has been disabled in the current environment
2478+
(for example, when running with `--no-harmony-temporal`).
2479+
24682480
<a id="ERR_NO_TYPESCRIPT"></a>
24692481

24702482
### `ERR_NO_TYPESCRIPT`
@@ -4472,6 +4484,7 @@ An error occurred trying to allocate memory. This should never happen.
44724484
[`QuicError`]: quic.md#class-quicerror
44734485
[`REPL`]: repl.md
44744486
[`ServerResponse`]: http.md#class-httpserverresponse
4487+
[`Temporal`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal
44754488
[`Writable`]: stream.md#class-streamwritable
44764489
[`child_process`]: child_process.md
44774490
[`cipher.getAuthTag()`]: crypto.md#ciphergetauthtag

doc/api/fs.md

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4799,7 +4799,11 @@ Stats {
47994799
atime: 2019-06-22T03:37:33.072Z,
48004800
mtime: 2019-06-22T03:36:54.583Z,
48014801
ctime: 2019-06-22T03:37:06.624Z,
4802-
birthtime: 2019-06-22T03:28:46.937Z
4802+
birthtime: 2019-06-22T03:28:46.937Z,
4803+
atimeInstant: 2019-06-22T03:37:33.071963Z,
4804+
mtimeInstant: 2019-06-22T03:36:54.5833518Z,
4805+
ctimeInstant: 2019-06-22T03:37:06.6235366Z,
4806+
birthtimeInstant: 2019-06-22T03:28:46.9372893Z
48034807
}
48044808
false
48054809
Stats {
@@ -4820,7 +4824,11 @@ Stats {
48204824
atime: 2019-06-22T03:36:56.619Z,
48214825
mtime: 2019-06-22T03:36:54.584Z,
48224826
ctime: 2019-06-22T03:36:54.584Z,
4823-
birthtime: 2019-06-22T03:26:47.711Z
4827+
birthtime: 2019-06-22T03:26:47.711Z,
4828+
atimeInstant: 2019-06-22T03:36:56.6188555Z,
4829+
mtimeInstant: 2019-06-22T03:36:54.584Z,
4830+
ctimeInstant: 2019-06-22T03:36:54.5838145Z,
4831+
birthtimeInstant: 2019-06-22T03:26:47.7107478Z
48244832
}
48254833
```
48264834
@@ -7525,6 +7533,9 @@ i.e. before the `'ready'` event is emitted.
75257533
<!-- YAML
75267534
added: v0.1.21
75277535
changes:
7536+
- version: REPLACEME
7537+
pr-url: https://github.com/nodejs/node/pull/60789
7538+
description: Added `Temporal.Instant` support.
75287539
- version:
75297540
- v22.0.0
75307541
- v20.13.0
@@ -7560,10 +7571,19 @@ Stats {
75607571
mtimeMs: 1318289051000.1,
75617572
ctimeMs: 1318289051000.1,
75627573
birthtimeMs: 1318289051000.1,
7574+
7575+
// Instances of Date
75637576
atime: Mon, 10 Oct 2011 23:24:11 GMT,
75647577
mtime: Mon, 10 Oct 2011 23:24:11 GMT,
75657578
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
7566-
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
7579+
birthtime: Mon, 10 Oct 2011 23:24:11 GMT,
7580+
7581+
// Instances of Temporal.Instant
7582+
atimeInstant: 2011-10-10T23:24:11.0001Z,
7583+
mtimeInstant: 2011-10-10T23:24:11.0001Z,
7584+
ctimeInstant: 2011-10-10T23:24:11.0001Z,
7585+
birthtimeInstant: 2011-10-10T23:24:11.0001Z
7586+
}
75677587
```
75687588
75697589
`bigint` version:
@@ -7588,10 +7608,19 @@ BigIntStats {
75887608
mtimeNs: 1318289051000000000n,
75897609
ctimeNs: 1318289051000000000n,
75907610
birthtimeNs: 1318289051000000000n,
7611+
7612+
// Instances of Date
75917613
atime: Mon, 10 Oct 2011 23:24:11 GMT,
75927614
mtime: Mon, 10 Oct 2011 23:24:11 GMT,
75937615
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
7594-
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
7616+
birthtime: Mon, 10 Oct 2011 23:24:11 GMT,
7617+
7618+
// Instances of Temporal.Instant
7619+
atimeInstant: 2011-10-10T23:24:11Z,
7620+
mtimeInstant: 2011-10-10T23:24:11Z,
7621+
ctimeInstant: 2011-10-10T23:24:11Z,
7622+
birthtimeInstant: 2011-10-10T23:24:11Z
7623+
}
75957624
```
75967625
75977626
#### `stats.isBlockDevice()`

lib/internal/errors.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,8 @@ E('ERR_NO_CRYPTO',
16391639
'Node.js is not compiled with OpenSSL crypto support', Error);
16401640
E('ERR_NO_ICU',
16411641
'%s is not supported on Node.js compiled without ICU', TypeError);
1642+
E('ERR_NO_TEMPORAL',
1643+
'Temporal is not supported in this environment', Error);
16421644
E('ERR_NO_TYPESCRIPT',
16431645
'Node.js is not compiled with TypeScript support', Error);
16441646
E('ERR_OPERATION_FAILED', 'Operation failed: %s', Error, TypeError);

lib/internal/fs/utils.js

Lines changed: 143 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const {
88
DatePrototypeGetTime,
99
ErrorCaptureStackTrace,
1010
FunctionPrototypeCall,
11+
MathFloor,
1112
MathMin,
1213
MathRound,
1314
Number,
@@ -22,6 +23,7 @@ const {
2223
Symbol,
2324
TypedArrayPrototypeAt,
2425
TypedArrayPrototypeIncludes,
26+
globalThis,
2527
} = primordials;
2628

2729
const { Buffer } = require('buffer');
@@ -32,6 +34,7 @@ const {
3234
ERR_INCOMPATIBLE_OPTION_PAIR,
3335
ERR_INVALID_ARG_TYPE,
3436
ERR_INVALID_ARG_VALUE,
37+
ERR_NO_TEMPORAL,
3538
ERR_OUT_OF_RANGE,
3639
},
3740
hideStackFrames,
@@ -43,10 +46,10 @@ const {
4346
isUint8Array,
4447
} = require('internal/util/types');
4548
const {
46-
kEmptyObject,
47-
once,
4849
deprecate,
4950
isWindows,
51+
kEmptyObject,
52+
once,
5053
setOwnProperty,
5154
} = require('internal/util');
5255
const { toPathIfFileURL } = require('internal/url');
@@ -62,6 +65,10 @@ const {
6265
const pathModule = require('path');
6366
const kType = Symbol('type');
6467
const kStats = Symbol('stats');
68+
const kPartialAtimeNs = Symbol('partialAtimeNs');
69+
const kPartialMtimeNs = Symbol('partialMtimeNs');
70+
const kPartialCtimeNs = Symbol('partialCtimeNs');
71+
const kPartialBirthtimeNs = Symbol('kPartialBirthtimeNs');
6572
const assert = require('internal/assert');
6673

6774
const {
@@ -430,6 +437,25 @@ function nsFromTimeSpecBigInt(sec, nsec) {
430437
return sec * kNsPerSecBigInt + nsec;
431438
}
432439

440+
// TODO(LiviaMedeiros): TemporalInstant primordial
441+
let TemporalInstant;
442+
443+
function instantFromNs(nsec) {
444+
TemporalInstant ??= globalThis.Temporal?.Instant;
445+
if (TemporalInstant === undefined) {
446+
throw new ERR_NO_TEMPORAL();
447+
}
448+
return new TemporalInstant(nsec);
449+
}
450+
451+
function instantFromTimeSpecMs(msec, nsec) {
452+
TemporalInstant ??= globalThis.Temporal?.Instant;
453+
if (TemporalInstant === undefined) {
454+
throw new ERR_NO_TEMPORAL();
455+
}
456+
return new TemporalInstant(BigInt(MathFloor(msec / kMsPerSec)) * kNsPerSecBigInt + BigInt(nsec));
457+
}
458+
433459
// The Date constructor performs Math.floor() on the absolute value
434460
// of the timestamp: https://tc39.es/ecma262/#sec-timeclip
435461
// Since there may be a precision loss when the timestamp is
@@ -490,6 +516,106 @@ const lazyDateFields = {
490516
},
491517
};
492518

519+
const lazyTemporalFields = {
520+
__proto__: null,
521+
atimeInstant: {
522+
__proto__: null,
523+
enumerable: true,
524+
configurable: true,
525+
get() {
526+
return setOwnProperty(this, 'atimeInstant',
527+
instantFromTimeSpecMs(this.atimeMs, this[kPartialAtimeNs]));
528+
},
529+
set(value) {
530+
setOwnProperty(this, 'atimeInstant', value);
531+
},
532+
},
533+
mtimeInstant: {
534+
__proto__: null,
535+
enumerable: true,
536+
configurable: true,
537+
get() {
538+
return setOwnProperty(this, 'mtimeInstant',
539+
instantFromTimeSpecMs(this.mtimeMs, this[kPartialMtimeNs]));
540+
},
541+
set(value) {
542+
setOwnProperty(this, 'mtimeInstant', value);
543+
},
544+
},
545+
ctimeInstant: {
546+
__proto__: null,
547+
enumerable: true,
548+
configurable: true,
549+
get() {
550+
return setOwnProperty(this, 'ctimeInstant',
551+
instantFromTimeSpecMs(this.ctimeMs, this[kPartialCtimeNs]));
552+
},
553+
set(value) {
554+
setOwnProperty(this, 'ctimeInstant', value);
555+
},
556+
},
557+
birthtimeInstant: {
558+
__proto__: null,
559+
enumerable: true,
560+
configurable: true,
561+
get() {
562+
return setOwnProperty(this, 'birthtimeInstant',
563+
instantFromTimeSpecMs(this.birthtimeMs, this[kPartialBirthtimeNs]));
564+
},
565+
set(value) {
566+
setOwnProperty(this, 'birthtimeInstant', value);
567+
},
568+
},
569+
};
570+
571+
const lazyTemporalBigIntFields = {
572+
__proto__: null,
573+
atimeInstant: {
574+
__proto__: null,
575+
enumerable: true,
576+
configurable: true,
577+
get() {
578+
return setOwnProperty(this, 'atimeInstant', instantFromNs(this.atimeNs));
579+
},
580+
set(value) {
581+
setOwnProperty(this, 'atimeInstant', value);
582+
},
583+
},
584+
mtimeInstant: {
585+
__proto__: null,
586+
enumerable: true,
587+
configurable: true,
588+
get() {
589+
return setOwnProperty(this, 'mtimeInstant', instantFromNs(this.mtimeNs));
590+
},
591+
set(value) {
592+
setOwnProperty(this, 'mtimeInstant', value);
593+
},
594+
},
595+
ctimeInstant: {
596+
__proto__: null,
597+
enumerable: true,
598+
configurable: true,
599+
get() {
600+
return setOwnProperty(this, 'ctimeInstant', instantFromNs(this.ctimeNs));
601+
},
602+
set(value) {
603+
setOwnProperty(this, 'ctimeInstant', value);
604+
},
605+
},
606+
birthtimeInstant: {
607+
__proto__: null,
608+
enumerable: true,
609+
configurable: true,
610+
get() {
611+
return setOwnProperty(this, 'birthtimeInstant', instantFromNs(this.birthtimeNs));
612+
},
613+
set(value) {
614+
setOwnProperty(this, 'birthtimeInstant', value);
615+
},
616+
},
617+
};
618+
493619
function BigIntStats(dev, mode, nlink, uid, gid, rdev, blksize,
494620
ino, size, blocks,
495621
atimeNs, mtimeNs, ctimeNs, birthtimeNs) {
@@ -508,6 +634,7 @@ function BigIntStats(dev, mode, nlink, uid, gid, rdev, blksize,
508634
ObjectSetPrototypeOf(BigIntStats.prototype, StatsBase.prototype);
509635
ObjectSetPrototypeOf(BigIntStats, StatsBase);
510636
ObjectDefineProperties(BigIntStats.prototype, lazyDateFields);
637+
ObjectDefineProperties(BigIntStats.prototype, lazyTemporalBigIntFields);
511638

512639
BigIntStats.prototype._checkModeProperty = function(property) {
513640
if (isWindows && (property === S_IFIFO || property === S_IFBLK ||
@@ -519,18 +646,23 @@ BigIntStats.prototype._checkModeProperty = function(property) {
519646

520647
function Stats(dev, mode, nlink, uid, gid, rdev, blksize,
521648
ino, size, blocks,
522-
atimeMs, mtimeMs, ctimeMs, birthtimeMs) {
649+
atimeS, atimeNs, mtimeS, mtimeNs, ctimeS, ctimeNs, birthtimeS, birthtimeNs) {
523650
FunctionPrototypeCall(StatsBase, this, dev, mode, nlink, uid, gid, rdev,
524651
blksize, ino, size, blocks);
525-
this.atimeMs = atimeMs;
526-
this.mtimeMs = mtimeMs;
527-
this.ctimeMs = ctimeMs;
528-
this.birthtimeMs = birthtimeMs;
652+
this.atimeMs = msFromTimeSpec(atimeS, atimeNs);
653+
this.mtimeMs = msFromTimeSpec(mtimeS, mtimeNs);
654+
this.ctimeMs = msFromTimeSpec(ctimeS, ctimeNs);
655+
this.birthtimeMs = msFromTimeSpec(birthtimeS, birthtimeNs);
656+
this[kPartialAtimeNs] = atimeNs;
657+
this[kPartialMtimeNs] = mtimeNs;
658+
this[kPartialCtimeNs] = ctimeNs;
659+
this[kPartialBirthtimeNs] = birthtimeNs;
529660
}
530661

531662
ObjectSetPrototypeOf(Stats.prototype, StatsBase.prototype);
532663
ObjectSetPrototypeOf(Stats, StatsBase);
533664
ObjectDefineProperties(Stats.prototype, lazyDateFields);
665+
ObjectDefineProperties(Stats.prototype, lazyTemporalFields);
534666

535667
Stats.prototype._checkModeProperty = function(property) {
536668
if (isWindows && (property === S_IFIFO || property === S_IFBLK ||
@@ -563,10 +695,10 @@ function getStatsFromBinding(stats, offset = 0) {
563695
stats[3 + offset], stats[4 + offset], stats[5 + offset],
564696
stats[6 + offset], stats[7 + offset], stats[8 + offset],
565697
stats[9 + offset],
566-
msFromTimeSpec(stats[10 + offset], stats[11 + offset]),
567-
msFromTimeSpec(stats[12 + offset], stats[13 + offset]),
568-
msFromTimeSpec(stats[14 + offset], stats[15 + offset]),
569-
msFromTimeSpec(stats[16 + offset], stats[17 + offset]),
698+
stats[10 + offset], stats[11 + offset], // atime
699+
stats[12 + offset], stats[13 + offset], // mtime
700+
stats[14 + offset], stats[15 + offset], // ctime
701+
stats[16 + offset], stats[17 + offset], // birthtime
570702
);
571703
}
572704

0 commit comments

Comments
 (0)