Parse Natural Dates
Parse natural language dates ("next Tuesday", "in 2 weeks")
Source Code
import fs from "fs";
import path from "path";
import * as chrono from "chrono-node";
const [inputPath, textField, outputField, outputPath, referenceDate = ""] = process.argv.slice(2);
if (!inputPath || !textField || !outputField || !outputPath) {
console.error("Usage: inputPath textField outputField outputPath [referenceDate]");
process.exit(1);
}
/**
* Get nested field value using dot notation
*/
function getField(obj, fieldPath) {
const parts = fieldPath.split(".");
let val = obj;
for (const part of parts) {
if (val == null) return undefined;
val = val[part];
}
return val;
}
/**
* Set nested field value using dot notation
*/
function setField(obj, fieldPath, value) {
const parts = fieldPath.split(".");
let current = obj;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
if (!(part in current)) {
current[part] = {};
}
current = current[part];
}
current[parts[parts.length - 1]] = value;
}
try {
console.log(`Parsing natural language dates...`);
console.log(` Input: ${inputPath}`);
console.log(` Text field: ${textField}`);
console.log(` Output field: ${outputField}`);
const raw = fs.readFileSync(inputPath, "utf-8");
const data = JSON.parse(raw);
const items = Array.isArray(data) ? data : data.items || data.results || [];
if (!Array.isArray(items)) {
console.error("Input must be a JSON array or object with array property");
process.exit(1);
}
const refDate = referenceDate ? new Date(referenceDate) : new Date();
console.log(` Reference date: ${refDate.toISOString()}`);
let parsed = 0;
let failed = 0;
const results = items.map((item) => {
const newItem = { ...item };
const text = getField(item, textField);
if (text) {
const parsedResults = chrono.parse(String(text), refDate);
if (parsedResults.length > 0) {
// Use the first parsed date
const parsedDate = parsedResults[0].start.date();
setField(newItem, outputField, parsedDate.toISOString());
parsed++;
} else {
setField(newItem, outputField, null);
failed++;
}
} else {
setField(newItem, outputField, null);
failed++;
}
return newItem;
});
// Ensure output directory exists
const dir = path.dirname(outputPath);
if (dir && dir !== ".") {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(outputPath, JSON.stringify(results, null, 2));
console.log(`\nā Parsed dates`);
console.log(` Total items: ${items.length}`);
console.log(` Parsed: ${parsed}`);
console.log(` Failed: ${failed}`);
console.log(` Written to: ${outputPath}`);
console.log(
JSON.stringify({
success: true,
inputPath,
outputPath,
total: items.length,
parsed,
failed,
})
);
} catch (error) {
console.error("Error:", error.message);
process.exit(1);
}