Skip to content

Commit a46ab03

Browse files
committed
fs: add Temporal.Instant support to Stats and BigIntStats
Signed-off-by: LiviaMedeiros <livia@cirno.name>
1 parent a9b0a83 commit a46ab03

6 files changed

Lines changed: 315 additions & 19 deletions

File tree

doc/api/errors.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,6 +2465,17 @@ 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
2477+
compiled with `Temporal` support disabled.
2478+
24682479
<a id="ERR_NO_TYPESCRIPT"></a>
24692480

24702481
### `ERR_NO_TYPESCRIPT`
@@ -4472,6 +4483,7 @@ An error occurred trying to allocate memory. This should never happen.
44724483
[`QuicError`]: quic.md#class-quicerror
44734484
[`REPL`]: repl.md
44744485
[`ServerResponse`]: http.md#class-httpserverresponse
4486+
[`Temporal`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal
44754487
[`Writable`]: stream.md#class-streamwritable
44764488
[`child_process`]: child_process.md
44774489
[`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+
'Node.js is not compiled with Temporal support', 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: 155 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,118 @@ 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+
const value = instantFromTimeSpecMs(this.atimeMs, this[kPartialAtimeNs]);
527+
setOwnProperty(this, 'atimeInstant', value);
528+
return value;
529+
},
530+
set(value) {
531+
setOwnProperty(this, 'atimeInstant', value);
532+
},
533+
},
534+
mtimeInstant: {
535+
__proto__: null,
536+
enumerable: true,
537+
configurable: true,
538+
get() {
539+
const value = instantFromTimeSpecMs(this.mtimeMs, this[kPartialMtimeNs]);
540+
setOwnProperty(this, 'mtimeInstant', value);
541+
return value;
542+
},
543+
set(value) {
544+
setOwnProperty(this, 'mtimeInstant', value);
545+
},
546+
},
547+
ctimeInstant: {
548+
__proto__: null,
549+
enumerable: true,
550+
configurable: true,
551+
get() {
552+
const value = instantFromTimeSpecMs(this.ctimeMs, this[kPartialCtimeNs]);
553+
setOwnProperty(this, 'ctimeInstant', value);
554+
return value;
555+
},
556+
set(value) {
557+
setOwnProperty(this, 'ctimeInstant', value);
558+
},
559+
},
560+
birthtimeInstant: {
561+
__proto__: null,
562+
enumerable: true,
563+
configurable: true,
564+
get() {
565+
const value = instantFromTimeSpecMs(this.birthtimeMs, this[kPartialBirthtimeNs]);
566+
setOwnProperty(this, 'birthtimeInstant', value);
567+
return value;
568+
},
569+
set(value) {
570+
setOwnProperty(this, 'birthtimeInstant', value);
571+
},
572+
},
573+
};
574+
575+
const lazyTemporalBigIntFields = {
576+
__proto__: null,
577+
atimeInstant: {
578+
__proto__: null,
579+
enumerable: true,
580+
configurable: true,
581+
get() {
582+
const value = instantFromNs(this.atimeNs);
583+
setOwnProperty(this, 'atimeInstant', value);
584+
return value;
585+
},
586+
set(value) {
587+
setOwnProperty(this, 'atimeInstant', value);
588+
},
589+
},
590+
mtimeInstant: {
591+
__proto__: null,
592+
enumerable: true,
593+
configurable: true,
594+
get() {
595+
const value = instantFromNs(this.mtimeNs);
596+
setOwnProperty(this, 'mtimeInstant', value);
597+
return value;
598+
},
599+
set(value) {
600+
setOwnProperty(this, 'mtimeInstant', value);
601+
},
602+
},
603+
ctimeInstant: {
604+
__proto__: null,
605+
enumerable: true,
606+
configurable: true,
607+
get() {
608+
const value = instantFromNs(this.ctimeNs);
609+
setOwnProperty(this, 'ctimeInstant', value);
610+
return value;
611+
},
612+
set(value) {
613+
setOwnProperty(this, 'ctimeInstant', value);
614+
},
615+
},
616+
birthtimeInstant: {
617+
__proto__: null,
618+
enumerable: true,
619+
configurable: true,
620+
get() {
621+
const value = instantFromNs(this.birthtimeNs);
622+
setOwnProperty(this, 'birthtimeInstant', value);
623+
return value;
624+
},
625+
set(value) {
626+
setOwnProperty(this, 'birthtimeInstant', value);
627+
},
628+
},
629+
};
630+
493631
function BigIntStats(dev, mode, nlink, uid, gid, rdev, blksize,
494632
ino, size, blocks,
495633
atimeNs, mtimeNs, ctimeNs, birthtimeNs) {
@@ -508,6 +646,7 @@ function BigIntStats(dev, mode, nlink, uid, gid, rdev, blksize,
508646
ObjectSetPrototypeOf(BigIntStats.prototype, StatsBase.prototype);
509647
ObjectSetPrototypeOf(BigIntStats, StatsBase);
510648
ObjectDefineProperties(BigIntStats.prototype, lazyDateFields);
649+
ObjectDefineProperties(BigIntStats.prototype, lazyTemporalBigIntFields);
511650

512651
BigIntStats.prototype._checkModeProperty = function(property) {
513652
if (isWindows && (property === S_IFIFO || property === S_IFBLK ||
@@ -519,18 +658,23 @@ BigIntStats.prototype._checkModeProperty = function(property) {
519658

520659
function Stats(dev, mode, nlink, uid, gid, rdev, blksize,
521660
ino, size, blocks,
522-
atimeMs, mtimeMs, ctimeMs, birthtimeMs) {
661+
atimeS, atimeNs, mtimeS, mtimeNs, ctimeS, ctimeNs, birthtimeS, birthtimeNs) {
523662
FunctionPrototypeCall(StatsBase, this, dev, mode, nlink, uid, gid, rdev,
524663
blksize, ino, size, blocks);
525-
this.atimeMs = atimeMs;
526-
this.mtimeMs = mtimeMs;
527-
this.ctimeMs = ctimeMs;
528-
this.birthtimeMs = birthtimeMs;
664+
this.atimeMs = msFromTimeSpec(atimeS, atimeNs);
665+
this.mtimeMs = msFromTimeSpec(mtimeS, mtimeNs);
666+
this.ctimeMs = msFromTimeSpec(ctimeS, ctimeNs);
667+
this.birthtimeMs = msFromTimeSpec(birthtimeS, birthtimeNs);
668+
this[kPartialAtimeNs] = atimeNs;
669+
this[kPartialMtimeNs] = mtimeNs;
670+
this[kPartialCtimeNs] = ctimeNs;
671+
this[kPartialBirthtimeNs] = birthtimeNs;
529672
}
530673

531674
ObjectSetPrototypeOf(Stats.prototype, StatsBase.prototype);
532675
ObjectSetPrototypeOf(Stats, StatsBase);
533676
ObjectDefineProperties(Stats.prototype, lazyDateFields);
677+
ObjectDefineProperties(Stats.prototype, lazyTemporalFields);
534678

535679
Stats.prototype._checkModeProperty = function(property) {
536680
if (isWindows && (property === S_IFIFO || property === S_IFBLK ||
@@ -563,10 +707,10 @@ function getStatsFromBinding(stats, offset = 0) {
563707
stats[3 + offset], stats[4 + offset], stats[5 + offset],
564708
stats[6 + offset], stats[7 + offset], stats[8 + offset],
565709
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]),
710+
stats[10 + offset], stats[11 + offset], // atime
711+
stats[12 + offset], stats[13 + offset], // mtime
712+
stats[14 + offset], stats[15 + offset], // ctime
713+
stats[16 + offset], stats[17 + offset], // birthtime
570714
);
571715
}
572716

0 commit comments

Comments
 (0)