1'use strict';
2const common = require('../common');
3
4const tmpdir = require('../common/tmpdir');
5tmpdir.refresh();
6
7const assert = require('assert');
8const fs = require('fs');
9
10// Check for Y2K38 support. For Windows, assume it's there. Windows
11// doesn't have `touch` and `date -r` which are used in the check for support.
12if (!common.isWindows) {
13  const testFilePath = `${tmpdir.path}/y2k38-test`;
14  const testFileDate = '204001020304';
15  const { spawnSync } = require('child_process');
16  const touchResult = spawnSync('touch',
17                                ['-t', testFileDate, testFilePath],
18                                { encoding: 'utf8' });
19  if (touchResult.status !== 0) {
20    common.skip('File system appears to lack Y2K38 support (touch failed)');
21  }
22
23  // On some file systems that lack Y2K38 support, `touch` will succeed but
24  // the time will be incorrect.
25  const dateResult = spawnSync('date',
26                               ['-r', testFilePath, '+%Y%m%d%H%M'],
27                               { encoding: 'utf8' });
28  if (dateResult.status === 0) {
29    if (dateResult.stdout.trim() !== testFileDate) {
30      common.skip('File system appears to lack Y2k38 support (date failed)');
31    }
32  } else {
33    // On some platforms `date` may not support the `-r` option. Usually
34    // this will result in a non-zero status and usage information printed.
35    // In this case optimistically proceed -- the earlier `touch` succeeded
36    // but validation that the file has the correct time is not easily possible.
37    assert.match(dateResult.stderr, /[Uu]sage:/);
38  }
39}
40
41// Ref: https://github.com/nodejs/node/issues/13255
42const path = `${tmpdir.path}/test-utimes-precision`;
43fs.writeFileSync(path, '');
44
45const Y2K38_mtime = 2 ** 31;
46fs.utimesSync(path, Y2K38_mtime, Y2K38_mtime);
47const Y2K38_stats = fs.statSync(path);
48assert.strictEqual(Y2K38_stats.mtime.getTime() / 1000, Y2K38_mtime);
49
50if (common.isWindows) {
51  // This value would get converted to (double)1713037251359.9998
52  const truncate_mtime = 1713037251360;
53  fs.utimesSync(path, truncate_mtime / 1000, truncate_mtime / 1000);
54  const truncate_stats = fs.statSync(path);
55  assert.strictEqual(truncate_stats.mtime.getTime(), truncate_mtime);
56
57  // test Y2K38 for windows
58  // This value if treaded as a `signed long` gets converted to -2135622133469.
59  // POSIX systems stores timestamps in {long t_sec, long t_usec}.
60  // NTFS stores times in nanoseconds in a single `uint64_t`, so when libuv
61  // calculates (long)`uv_timespec_t.tv_sec` we get 2's complement.
62  const overflow_mtime = 2159345162531;
63  fs.utimesSync(path, overflow_mtime / 1000, overflow_mtime / 1000);
64  const overflow_stats = fs.statSync(path);
65  assert.strictEqual(overflow_stats.mtime.getTime(), overflow_mtime);
66}
67