Skip to content

Commit 3ae564b

Browse files
authored
feat(fs/unstable): add utime and utimeSync (#6446)
1 parent e5c25ed commit 3ae564b

File tree

5 files changed

+145
-0
lines changed

5 files changed

+145
-0
lines changed

_tools/check_docs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const ENTRY_POINTS = [
7878
"../fs/unstable_symlink.ts",
7979
"../fs/unstable_truncate.ts",
8080
"../fs/unstable_types.ts",
81+
"../fs/unstable_utime.ts",
8182
"../html/mod.ts",
8283
"../html/unstable_is_valid_custom_element_name.ts",
8384
"../http/mod.ts",

_tools/node_test_runner/run_test.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import "../../fs/unstable_symlink_test.ts";
6363
import "../../fs/unstable_truncate_test.ts";
6464
import "../../fs/unstable_lstat_test.ts";
6565
import "../../fs/unstable_chmod_test.ts";
66+
import "../../fs/unstable_utime_test.ts";
6667

6768
for (const testDef of testDefinitions) {
6869
test(testDef.name, testDef.fn);

fs/deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"./unstable-real-path": "./unstable_real_path.ts",
2727
"./unstable-rename": "./unstable_rename.ts",
2828
"./unstable-stat": "./unstable_stat.ts",
29+
"./unstable-utime": "./unstable_utime.ts",
2930
"./unstable-symlink": "./unstable_symlink.ts",
3031
"./unstable-truncate": "./unstable_truncate.ts",
3132
"./unstable-types": "./unstable_types.ts",

fs/unstable_utime.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2018-2025 the Deno authors. MIT license.
2+
3+
import { getNodeFs, isDeno } from "./_utils.ts";
4+
import { mapError } from "./_map_error.ts";
5+
6+
/** Changes the access (`atime`) and modification (`mtime`) times of a file
7+
* system object referenced by `path`. Given times are either in seconds
8+
* (UNIX epoch time) or as `Date` objects.
9+
*
10+
* Requires `allow-write` permission for the target path
11+
*
12+
* @example Usage
13+
*
14+
* ```ts
15+
* import { assert } from "@std/assert"
16+
* import { utime } from "@std/fs/unstable-utime";
17+
* import { stat } from "@std/fs/unstable-stat"
18+
*
19+
* const newAccessDate = new Date()
20+
* const newModifiedDate = new Date()
21+
*
22+
* const fileBefore = await Deno.stat("README.md")
23+
* await Deno.utime("README.md", newAccessDate, newModifiedDate)
24+
* const fileAfter = await Deno.stat("README.md")
25+
*
26+
* assert(fileBefore.atime !== fileAfter.atime)
27+
* assert(fileBefore.mtime !== fileAfter.mtime)
28+
* ```
29+
* @tags allow-write
30+
* @category File System
31+
* @param path The path to the file to be updated
32+
* @param atime The new access time
33+
* @param mtime The new modification time
34+
*/
35+
export async function utime(
36+
path: string | URL,
37+
atime: number | Date,
38+
mtime: number | Date,
39+
): Promise<void> {
40+
if (isDeno) {
41+
await Deno.utime(path, atime, mtime);
42+
} else {
43+
try {
44+
await getNodeFs().promises.utimes(path, atime, mtime);
45+
return;
46+
} catch (error) {
47+
throw mapError(error);
48+
}
49+
}
50+
}
51+
52+
/** Synchronously changes the access (`atime`) and modification (`mtime`)
53+
* times of the file stream resource. Given times are either in seconds
54+
* (UNIX epoch time) or as `Date` objects.
55+
*
56+
* Requires `allow-write` permission for the target path
57+
*
58+
* @example Usage
59+
*
60+
* ```ts
61+
* import { assert } from "@std/assert"
62+
* import { utimeSync } from "@std/fs/unstable-utime";
63+
* import { stat } from "@std/fs/unstable-stat"
64+
*
65+
* const newAccessDate = new Date()
66+
* const newModifiedDate = new Date()
67+
*
68+
* const fileBefore = await Deno.stat("README.md")
69+
* Deno.utimeSync("README.md", newAccessDate, newModifiedDate)
70+
* const fileAfter = await Deno.stat("README.md")
71+
*
72+
* assert(fileBefore.atime !== fileAfter.atime)
73+
* assert(fileBefore.mtime !== fileAfter.mtime)
74+
* ```
75+
* @tags allow-write
76+
* @category File System
77+
* @param path The path to the file to be updated
78+
* @param atime The new access time
79+
* @param mtime The new modification time
80+
*/
81+
export function utimeSync(
82+
path: string | URL,
83+
atime: number | Date,
84+
mtime: number | Date,
85+
): void {
86+
if (isDeno) {
87+
return Deno.utimeSync(path, atime, mtime);
88+
} else {
89+
try {
90+
getNodeFs().utimesSync(path, atime, mtime);
91+
} catch (error) {
92+
throw mapError(error);
93+
}
94+
}
95+
}

fs/unstable_utime_test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2018-2025 the Deno authors. MIT license.
2+
import { assert, assertRejects, assertThrows } from "@std/assert";
3+
import { utime, utimeSync } from "./unstable_utime.ts";
4+
import { NotFound } from "./unstable_errors.js";
5+
6+
import { statSync } from "node:fs";
7+
8+
const now = new Date();
9+
const filePath = "fs/testdata/copy_file.txt";
10+
11+
Deno.test("utime() change atime and mtime date", async () => {
12+
const fileBefore = statSync(filePath);
13+
14+
await utime(filePath, now, now);
15+
16+
const fileAfter = statSync(filePath);
17+
18+
assert(fileBefore.atime != fileAfter.atime);
19+
assert(fileBefore.mtime != fileAfter.mtime);
20+
});
21+
22+
Deno.test("utime() fail on NotFound file", async () => {
23+
const randomFile = "foo.txt";
24+
25+
await assertRejects(async () => {
26+
await utime(randomFile, now, now);
27+
}, NotFound);
28+
});
29+
30+
Deno.test("utimeSync() change atime and mtime data", () => {
31+
const fileBefore = statSync(filePath);
32+
33+
utimeSync(filePath, now, now);
34+
35+
const fileAfter = statSync(filePath);
36+
37+
assert(fileBefore.atime != fileAfter.atime);
38+
assert(fileBefore.mtime != fileAfter.mtime);
39+
});
40+
41+
Deno.test("utimeSync() fail on NotFound file", () => {
42+
const randomFile = "foo.txt";
43+
44+
assertThrows(() => {
45+
utimeSync(randomFile, now, now);
46+
}, NotFound);
47+
});

0 commit comments

Comments
 (0)