Filter by Date Range
Filter items by date range with support for relative dates
Source Code
import fs from "fs";
import path from "path";
const [inputPath, dateField, startArg, endArg, outputPath] =
process.argv.slice(2);
if (!inputPath || !dateField || !startArg || !endArg || !outputPath) {
console.error("Usage: inputPath dateField start end outputPath");
process.exit(1);
}
/**
* Get nested field value using dot notation
*/
function getField(obj, fieldPath) {
const parts = fieldPath.split(".");
let value = obj;
for (const part of parts) {
if (value == null) return undefined;
value = value[part];
}
return value;
}
/**
* Parse relative date string like "7d", "1m", "1y"
*/
function parseRelativeDate(str) {
if (str === "now") {
return new Date();
}
const match = str.match(/^(\d+)([dmywh])$/);
if (!match) {
return null;
}
const [, num, unit] = match;
const amount = parseInt(num);
const now = new Date();
switch (unit) {
case "h":
return new Date(now.getTime() - amount * 60 * 60 * 1000);
case "d":
return new Date(now.getTime() - amount * 24 * 60 * 60 * 1000);
case "w":
return new Date(now.getTime() - amount * 7 * 24 * 60 * 60 * 1000);
case "m":
const monthsAgo = new Date(now);
monthsAgo.setMonth(monthsAgo.getMonth() - amount);
return monthsAgo;
case "y":
const yearsAgo = new Date(now);
yearsAgo.setFullYear(yearsAgo.getFullYear() - amount);
return yearsAgo;
default:
return null;
}
}
/**
* Parse date from string (ISO or relative)
*/
function parseDate(str) {
// Try relative first
const relative = parseRelativeDate(str);
if (relative) return relative;
// Try ISO/standard date
const date = new Date(str);
return isNaN(date.getTime()) ? null : date;
}
try {
console.log(`Reading ${inputPath}...`);
const raw = fs.readFileSync(inputPath, "utf-8");
const data = JSON.parse(raw);
const items = Array.isArray(data)
? data
: data.items || data.results || data.messages || [];
if (!Array.isArray(items)) {
console.error("Input must be a JSON array or object with array property");
process.exit(1);
}
const startDate = parseDate(startArg);
const endDate = parseDate(endArg);
if (!startDate) {
console.error(`Invalid start date: ${startArg}`);
process.exit(1);
}
if (!endDate) {
console.error(`Invalid end date: ${endArg}`);
process.exit(1);
}
console.log(
`Filtering ${items.length} items where ${dateField} between ${startDate.toISOString()} and ${endDate.toISOString()}`
);
const filtered = items.filter((item) => {
const fieldValue = getField(item, dateField);
if (!fieldValue) return false;
const itemDate = new Date(fieldValue);
if (isNaN(itemDate.getTime())) return false;
return itemDate >= startDate && itemDate <= endDate;
});
// Ensure output directory exists
const dir = path.dirname(outputPath);
if (dir && dir !== ".") {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(outputPath, JSON.stringify(filtered, null, 2));
console.log(`\nā Filtered ${items.length} ā ${filtered.length} items`);
console.log(` Date field: ${dateField}`);
console.log(` Range: ${startDate.toISOString().split("T")[0]} to ${endDate.toISOString().split("T")[0]}`);
console.log(` Written to: ${outputPath}`);
console.log(
JSON.stringify({
success: true,
outputPath,
inputCount: items.length,
outputCount: filtered.length,
dateRange: {
start: startDate.toISOString(),
end: endDate.toISOString(),
},
})
);
} catch (error) {
console.error("Error:", error.message);
process.exit(1);
}