@curtisdigital/excel-datetime-parser
v1.0.0
Published
Robust date/time parser for messy Excel data. Zero dependencies, edge-runtime compatible.
Maintainers
Readme
@curtisdigital/excel-datetime-parser
Robust date/time parser for messy Excel data. Zero runtime dependencies, edge-runtime compatible.
Why?
Excel spreadsheets are chaos. Dates come as serial numbers, times as decimals, strings in random formats, or just "TBD". This library normalizes all of that into clean, consistent output.
Key features:
- 🎯 Predictable: Returns
string | null, never throws - 🪶 Tiny: Zero runtime dependencies, < 2KB minified
- ⚡ Edge-ready: Works in Cloudflare Workers, Vercel Functions
- 📝 TypeScript: Full type safety
Installation
npm install @curtisdigital/excel-datetime-parserOr try it out instantly with npx:
npx @curtisdigital/excel-datetime-parserUsage
import { parseDate, parseTime } from '@curtisdigital/excel-datetime-parser';
// === DATE PARSING ===
parseDate(45993) // "2025-12-02" (Excel serial number)
parseDate("12/2/2025") // "2025-12-02" (US format)
parseDate("2025-12-02") // "2025-12-02" (ISO - pass through)
parseDate(new Date('2025-12-02')) // "2025-12-02" (JS Date object)
parseDate("TBD") // null
parseDate("12/23/2025 - 12/26/2025") // null (date ranges rejected)
parseDate("") // null
parseDate(null) // null
// === TIME PARSING ===
parseTime(0.375) // "09:00:00" (Excel decimal)
parseTime("14:00") // "14:00:00" (24-hour)
parseTime("14:00:00") // "14:00:00" (24-hour with seconds)
parseTime("3:30PM") // "15:30:00" (12-hour, no space)
parseTime(new Date('2025-01-01T14:30:00Z')) // "14:30:00"
parseTime("MEMORIAL DAY HOLIDAY") // null
parseTime("") // null
parseTime(null) // nullAPI
parseDate(value: unknown): string | null
Parses any value that might represent a date into ISO format (YYYY-MM-DD).
Supported inputs:
| Input Type | Example | Output |
|------------|---------|--------|
| null / undefined | null | null |
| Empty string | "", " " | null |
| JavaScript Date | new Date('2025-12-02') | "2025-12-02" |
| Excel serial | 45993 | "2025-12-02" |
| ISO string | "2025-12-02" | "2025-12-02" |
| US format | "12/2/2025" | "2025-12-02" |
| Date range | "12/23/2025 - 12/26/2025" | null |
| Other strings | "TBD", "Q4 2025" | null |
parseTime(value: unknown): string | null
Parses any value that might represent a time into 24-hour format (HH:MM:SS).
Supported inputs:
| Input Type | Example | Output |
|------------|---------|--------|
| null / undefined | null | null |
| Empty string | "", " " | null |
| JavaScript Date | new Date() | "14:30:45" |
| Excel decimal | 0.375 | "09:00:00" |
| 24-hour (no sec) | "14:00" | "14:00:00" |
| 24-hour (with sec) | "14:00:00" | "14:00:00" |
| 12-hour (no space) | "3:30PM" | "15:30:00" |
| Holiday text | "MEMORIAL DAY" | null |
| Other strings | "Morning" | null |
Edge Cases
Whitespace
All string inputs are trimmed, including Unicode non-breaking spaces (NBSP):
parseDate(" 2025-12-02 ") // "2025-12-02"
parseDate("\u00A02025-12-02") // "2025-12-02" (NBSP)Excel Serial Numbers
Handles the infamous Excel 1900 leap year bug (Excel incorrectly thinks Feb 29, 1900 existed):
parseDate(1) // "1900-01-01"
parseDate(60) // Handles the fake Feb 29, 1900
parseDate(61) // "1900-03-01"12-Hour Time Format
Per requirements, no space before AM/PM:
parseTime("3:30PM") // "15:30:00" ✓
parseTime("3:30 PM") // null ✗Date Ranges
Date ranges are explicitly rejected (return null):
parseDate("12/23/2025 - 12/26/2025") // nullAdvanced Usage
Utility functions are also exported for custom use cases:
import {
isExcelSerialDate,
isExcelTimeDecimal,
excelSerialToDate,
excelDecimalToTime,
normalizeInput
} from '@curtisdigital/excel-datetime-parser';
// Check if a number looks like an Excel serial date
isExcelSerialDate(45993) // true
isExcelSerialDate(0.5) // false (that's a time)
// Check if a number looks like an Excel time
isExcelTimeDecimal(0.375) // true
isExcelTimeDecimal(45993) // false (that's a date)
// Convert Excel serial to JS Date
const date = excelSerialToDate(45993);
// Convert Excel decimal to time string
excelDecimalToTime(0.375) // "09:00:00"
// Normalize input (trim, handle NBSP)
normalizeInput(" hello ") // "hello"
normalizeInput("\u00A0") // null (empty after trim)Compatibility
- ✅ Node.js 18+
- ✅ Cloudflare Workers
- ✅ Vercel Edge Functions
- ✅ Deno
- ✅ Bun
- ✅ Browsers (ESM)
License
MIT
