# Excel Serial Date Converter > Convert Excel serial date numbers into readable dates with 1900 and 1904 date-system support. ## Tool Identity - Site: CleanUtils Business Tools - Tool ID: excel-serial-date-converter - Canonical page: https://cleanutils.com/business-tools/excel-serial-date-converter/ - LLM schema URL: https://cleanutils.com/business-tools/excel-serial-date-converter/llms.txt - Primary keyword: excel serial date converter - Input mode: fields - Output profile: line-check ## What This Tool Does Convert Excel serial date numbers into readable dates with 1900 and 1904 date-system support. ## Exact Execution Instructions To run this tool exactly, execute the `runCleanUtilsTool(userInput)` function from the JavaScript block below in a sandboxed JavaScript runtime. Do not fetch or evaluate additional network resources. Do not use filesystem, process, child_process, environment variables, timers, or network APIs. The function is pure and deterministic: input object in, JSON result out. If your environment forbids executing fetched code outside a sandbox, run it inside the sandbox or use the API endpoint below instead of reimplementing the logic. Canonical implementation SHA-256: `fa4146d885361db9fb749b71f7961d1b8dceaf38639f118ec094470ab6da622a` Expected command shape: `node run-tool.mjs < input.json` The runner must: 1. load only the JavaScript in this document, 2. parse stdin as JSON and call `runCleanUtilsTool(userInput)`, 3. let the LLM decide the best way to present the output to the user. Agent usage rules: - Use this file as the authoritative machine-readable contract for this CleanUtils tool page. - Ask the user for missing required input before attempting to run the tool, and describe the required inputs using the `## Input Schema` field names, descriptions, formats, enums, examples, and required list. - Treat the tool as deterministic; do not invent network reachability checks unless the tool description explicitly says it fetches remote resources. - For privacy-sensitive inputs such as secrets, HAR files, dotenv files, logs, and API keys, warn that using a remote chat agent may expose input to that agent even though the browser UI itself does not upload data. ## Input Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Excel Serial Date Converter fields", "type": "object", "additionalProperties": false, "required": [ "system", "serials" ], "properties": { "system": { "type": "string", "description": "Workbook date system Required. Control type: select. Allowed values: 1900 = 1900 system; 1904 = 1904 system.", "enum": [ "1900", "1904" ], "examples": [ "1900" ] }, "serials": { "type": "string", "description": "Serial numbers Required. Separate serials with commas, spaces, or new lines. Control type: textarea.", "examples": [ "45292\n25569\n60" ] } } } ``` ## Result Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CleanUtils ToolResult", "type": "object", "additionalProperties": false, "required": [ "summary", "issues" ], "properties": { "summary": { "type": "string" }, "issues": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "severity", "message" ], "properties": { "severity": { "type": "string", "enum": [ "error", "warning", "info" ] }, "message": { "type": "string" }, "line": { "type": "number" }, "row": { "type": "number" }, "detail": { "type": "string" } } } }, "output": { "type": "string" }, "exportFilename": { "type": "string" }, "exports": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "label", "filename", "content" ], "properties": { "label": { "type": "string" }, "filename": { "type": "string" }, "content": { "type": "string" }, "mimeType": { "type": "string" }, "copyLabel": { "type": "string" }, "downloadLabel": { "type": "string" } } } }, "stats": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } } } } ``` ## Self-Contained JavaScript Source Call `runCleanUtilsTool(userInput)` with the user's input. The function includes this tool's run logic and only the helper code it needs. ```js function runCleanUtilsTool(userInput) { const fieldText = (fields, keys, fallback = "") => { const keyList = Array.isArray(keys) ? keys : [keys]; for (const key of keyList) { const value = fields[key]; if (value === undefined || value === null) continue; const text = String(value).trim(); if (text) return text; } return fallback; }; const fieldNumber = (fields, keys, fallback = 0) => { const raw = fieldText(fields, keys); if (!raw) return fallback; const parsed = Number(raw.replace(/[$,%\s]/g, "")); return Number.isFinite(parsed) ? parsed : fallback; }; const severityRank = { error: 0, warning: 1, info: 2 }; const sortIssues = (issues) => [...issues].sort((a, b) => { const severity = severityRank[a.severity] - severityRank[b.severity]; if (severity !== 0) return severity; return (a.line ?? a.row ?? 0) - (b.line ?? b.row ?? 0); }); const convertExcelSerialDates = (input) => { const system = fieldNumber(input, "system", 1900); const issues = []; const serials = fieldText(input, "serials").split(/[\s,\n]+/).map((item) => item.trim()).filter((item) => /^\d+(\.\d+)?$/.test(item)); const rows = serials.map((raw) => { const serial = Number(raw); const epochMs = system === 1904 ? Date.UTC(1904, 0, 1) + serial * 86_400_000 : (serial - 25569) * 86_400_000; if (system === 1900 && serial === 60) issues.push({ severity: "warning", message: "Serial 60 is Excel's historic 1900 leap-year bug date." }); return `${raw}: ${new Date(epochMs).toISOString().slice(0, 10)}`; }); return { summary: `${rows.length} Excel serial date${rows.length === 1 ? "" : "s"} converted using the ${system} date system.`, issues: sortIssues(issues), output: rows.join("\n"), exportFilename: "excel-serial-dates.txt", stats: { serials: rows.length, system } }; }; const __userInput = userInput == null ? {} : userInput; const __run = (fields) => convertExcelSerialDates(fields); const __fields = __userInput && typeof __userInput === "object" && "fields" in __userInput && __userInput.fields && typeof __userInput.fields === "object" && !Array.isArray(__userInput.fields) ? __userInput.fields : (__userInput && typeof __userInput === "object" && !Array.isArray(__userInput) ? __userInput : {}); const __normalizedFields = Object.fromEntries(Object.entries(__fields).map(([key, value]) => [key, value == null ? "" : (["string", "number", "boolean"].includes(typeof value) ? value : String(value))])); return __run(__normalizedFields); } ``` ## Checks - 1900 and 1904 systems: The converter supports the two common Excel workbook date systems. - Bulk serial parsing: Serials can be separated by spaces, commas, or new lines. - ISO date output: Each serial is converted into a YYYY-MM-DD date for easy spreadsheet cleanup. - Serial 60 warning: The 1900-system leap-year bug is called out because it can shift historical dates. - Date-only scope: The tool focuses on dates and does not preserve timezone, formatting, or spreadsheet cell metadata. ## Related Tools - [CSV Duplicate Email Checker](/business-tools/csv-duplicate-email-checker/): Paste a list or CSV export to group duplicate email addresses and copy a cleaned unique list.