Chapter 19 - Keeping Time, Scheduling Tasks, and Launching Programs (JavaScript)
Here's a JavaScript-flavoured version of the same concepts, with small JS/Node examples for each idea.
Time basics
Epoch timestamp with Date.now and human time
- Unix epoch: same midnight Jan 1, 1970 UTC.
Date.now()→ milliseconds since epoch (not seconds like Python).new Date().toString()→ human-readable string.
const nowMs = Date.now();
console.log(nowMs); // e.g. 1773813875350
console.log(nowMs / 1000); // seconds (like Python's time.time())
console.log(new Date().toString()); // 'Tue Mar 17 2026 23:05:38 GMT-0700'
console.log(new Date(nowMs).toString()); // same time
Profiling code with Date.now or performance.now
Measure elapsed time by subtracting timestamps. performance.now() gives sub-millisecond precision.
const { performance } = require("perf_hooks");
function calculateProduct() {
let product = 1n; // BigInt for huge numbers
for (let i = 1n; i <= 100000n; i++) {
product *= i;
}
return product;
}
const startTime = performance.now();
const result = calculateProduct();
const endTime = performance.now();
console.log(`It took ${(endTime - startTime) / 1000} seconds to calculate.`);
For deeper profiling, Node has --prof and the built-in inspector module.
Pausing with setTimeout and sleep helpers
JavaScript is async by nature — there's no blocking sleep(). Use setTimeout with a promise:
function sleep(seconds) {
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
async function main() {
for (let i = 0; i < 3; i++) {
console.log("Tick");
await sleep(1);
console.log("Tock");
await sleep(1);
}
await sleep(5); // extra pause
}
main();
For synchronous blocking (not recommended in production), use Atomics.wait:
function sleepSync(seconds) {
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, seconds * 1000);
}
Project 14: Super Stopwatch
Same goal: track lap times with ENTER, exit with CTRL‑C.
const readline = require("readline");
const rl = readline.createInterface({ input: process.stdin });
console.log("Press ENTER to begin and to mark laps. Ctrl-C quits.");
let startTime, lastTime, lapNumber;
rl.on("line", () => {
if (!startTime) {
console.log("Started.");
startTime = Date.now();
lastTime = startTime;
lapNumber = 1;
return;
}
const now = Date.now();
const lapTime = ((now - lastTime) / 1000).toFixed(2);
const totalTime = ((now - startTime) / 1000).toFixed(2);
console.log(`Lap #${lapNumber}: ${totalTime} (${lapTime})`);
lapNumber++;
lastTime = now;
});
process.on("SIGINT", () => {
console.log("\nDone.");
process.exit();
});
Date objects (datetime equivalent)
Date objects: specific moments
new Date() → current date/time; new Date(year, month, ...) → specific moment. Months are 0-based in JavaScript (0 = January).
const now = new Date();
console.log(now); // 2026-02-27T19:10:49.727Z
const dt = new Date(2026, 9, 21, 16, 29, 0); // month 9 = October
console.log(dt.getFullYear(), dt.getMonth() + 1, dt.getDate()); // 2026 10 21
console.log(dt.getHours(), dt.getMinutes(), dt.getSeconds()); // 16 29 0
Convert epoch timestamp to Date:
console.log(new Date(1000000 * 1000)); // 1970-01-12T13:46:40.000Z
console.log(new Date(Date.now())); // current moment
Compare dates (compare timestamps, not objects directly):
const halloween2026 = new Date(2026, 9, 31);
const newYears2027 = new Date(2027, 0, 1);
const oct312026 = new Date(2026, 9, 31);
console.log(halloween2026.getTime() === oct312026.getTime()); // true
console.log(halloween2026 > newYears2027); // false
console.log(newYears2027 > halloween2026); // true
Durations (timedelta equivalent)
JavaScript has no built-in timedelta. Work with millisecond arithmetic instead:
const MS_PER_DAY = 24 * 60 * 60 * 1000;
const MS_PER_HOUR = 60 * 60 * 1000;
const MS_PER_MINUTE = 60 * 1000;
// 11 days, 10 hours, 9 minutes, 8 seconds
const deltaMs =
11 * MS_PER_DAY + 10 * MS_PER_HOUR + 9 * MS_PER_MINUTE + 8 * 1000;
console.log(deltaMs / 1000); // 986948 total seconds
// Date arithmetic
const now = new Date();
const thousandDays = 1000 * MS_PER_DAY;
console.log(new Date(now.getTime() + thousandDays)); // 1000 days from now
More examples:
const oct21st = new Date(2026, 9, 21, 16, 29, 0);
const aboutThirtyYears = 365 * 30 * MS_PER_DAY;
console.log(new Date(oct21st.getTime() - aboutThirtyYears)); // ~1996-10-28
console.log(new Date(oct21st.getTime() - 2 * aboutThirtyYears)); // ~1966-11-05
Pausing until a specific date
function sleep(seconds) {
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
async function waitUntil() {
const halloween2039 = new Date(2039, 9, 31);
while (new Date() < halloween2039) {
await sleep(1);
}
// continue after Halloween 2039
}
Formatting dates
JavaScript has toLocaleDateString and toLocaleString with options, or manual formatting:
const oct21st = new Date(2026, 9, 21, 16, 29, 0);
// Using toLocaleString with options
console.log(
oct21st.toLocaleString("en-US", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
})
);
// '10/21/2026, 16:29:00'
console.log(
oct21st.toLocaleString("en-US", { hour: "2-digit", minute: "2-digit" })
);
// '04:29 PM'
console.log(
oct21st.toLocaleString("en-US", { month: "long", year: "2-digit" })
);
// "October 26"
For Python-style strftime format strings, use the date-fns package:
npm install date-fns
const { format } = require("date-fns");
const oct21st = new Date(2026, 9, 21, 16, 29, 0);
console.log(format(oct21st, "yyyy/MM/dd HH:mm:ss")); // '2026/10/21 16:29:00'
console.log(format(oct21st, "hh:mm a")); // '04:29 PM'
console.log(format(oct21st, "MMMM 'of' ''yy")); // "October of '26"
Parsing date strings
Built-in new Date(string) handles ISO 8601 and common formats:
console.log(new Date("October 21, 2026")); // 2026-10-21T...
console.log(new Date("2026/10/21 16:29:00")); // 2026-10-21T...
For custom format parsing, use date-fns:
const { parse } = require("date-fns");
console.log(parse("October 21, 2026", "MMMM dd, yyyy", new Date()));
// 2026-10-21T00:00:00
console.log(parse("2026/10/21 16:29:00", "yyyy/MM/dd HH:mm:ss", new Date()));
// 2026-10-21T16:29:00
Review of JS time functions
Summary of types:
- Epoch timestamp: milliseconds since 1970-01-01 (
Date.now()). Dateobject: specific moment (year, month, day, hour, minute, second, millisecond).- No built-in duration type — use millisecond arithmetic.
Key functions: Date.now, new Date(...), date.getTime(), date.getFullYear/getMonth/getDate/getHours/getMinutes/getSeconds, toLocaleString, date-fns for format/parse.
Launching programs with child_process
execSync and spawnSync (blocking — like subprocess.run)
const { execSync, spawnSync } = require("child_process");
// macOS
spawnSync("open", ["/System/Applications/Calculator.app"]);
// Linux
// spawnSync('/usr/bin/gnome-calculator');
// Windows
// spawnSync('C:\\Windows\\System32\\calc.exe');
spawnSync returns an object with .status (exit code) and .stdout/.stderr buffers.
spawn (non-blocking — like subprocess.Popen)
spawn starts a process and returns immediately; your script continues.
const { spawn } = require("child_process");
const calcProc = spawn("open", ["/System/Applications/Calculator.app"]);
calcProc.on("exit", (code) => {
console.log(`Exited with code ${code}`);
});
// Kill a process
// calcProc.kill();
Passing command line arguments
Arguments go in the array after the command:
const { spawnSync } = require("child_process");
// macOS: open a file in default app
spawnSync("open", ["/Users/Al/hello.txt"]);
// Windows equivalent:
// spawnSync('C:\\Windows\\notepad.exe', ['C:\\Users\\Al\\hello.txt']);
Capturing output from commands
Use execSync with encoding, or spawnSync:
const { execSync } = require("child_process");
// macOS/Linux
const output = execSync("ping -c 4 nostarch.com", { encoding: "utf-8" });
console.log(output);
// Windows: ping -n 4 nostarch.com
Or with spawnSync:
const { spawnSync } = require("child_process");
const proc = spawnSync("ping", ["-c", "4", "nostarch.com"], {
encoding: "utf-8",
});
console.log(proc.stdout);
Scheduling with OS tools
Same OS schedulers apply:
- Windows: Task Scheduler.
- macOS:
launchd. - Linux:
cron.
In Node, you can also use packages like node-cron for in-process scheduling:
npm install node-cron
const cron = require("node-cron");
cron.schedule("0 9 * * *", () => {
console.log("Running task at 9:00 AM every day");
});
Opening files with default applications
const { execSync } = require("child_process");
const fs = require("fs");
fs.writeFileSync("hello.txt", "Hello, world!", "utf-8");
// macOS
execSync("open hello.txt");
// Windows
// execSync('start hello.txt', { shell: true });
// Linux
// execSync('xdg-open hello.txt');
The open package provides a cross-platform alternative:
npm install open
const open = require("open");
await open("hello.txt");
Project 15: Simple Countdown
Step 1: Countdown loop
function sleep(seconds) {
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
async function countdown() {
let timeLeft = 60;
while (timeLeft > 0) {
console.log(timeLeft);
await sleep(1);
timeLeft--;
}
// TODO: play sound/open file
}
countdown();
Step 2: Play sound or open something
const { execSync } = require("child_process");
// macOS:
// execSync('open alarm.wav');
// Windows:
// execSync('start alarm.wav', { shell: true });
// Or use the open package:
// const open = require('open');
// await open('alarm.wav');
You can instead open a website with the open package or use child_process to launch a browser.
Overall idea of the chapter
Chapter 19 in JavaScript: time handling with Date.now() (milliseconds, not seconds), Date objects for moments, millisecond arithmetic for durations (no built-in timedelta), formatting with toLocaleString or date-fns, async sleep with setTimeout promises, and launching programs with child_process (spawnSync/execSync for blocking, spawn for non-blocking). OS schedulers (Task Scheduler, launchd, cron) or node-cron handle recurring tasks.