/*
Program goal:
-------------
Sort a list of date strings in the format "YYYY-MM-DD".
Approach:
1. Parse each string into a Date object using a safe, explicit parser.
2. Sort using Array.prototype.sort() with a comparator.
3. Convert back to strings and print results.
Architecture notes:
-------------------
- Parsing is isolated in a dedicated function for clarity and testability.
- Sorting uses the built-in sort() with a comparator (O(n log n)).
- Error handling: invalid formats are detected and reported.
- Edge cases: malformed strings, invalid ranges, leap years.
- Performance: Date parsing is fast; sorting is O(n log n).
- Memory: minimal; only an array of small objects.
- Security: avoids unsafe parsing and timezone surprises.
*/
/*
Parse a date string into a Date object.
Throws an error with a clear message on failure.
*/
function parseDate(s: string): Date {
// Basic structural validation: YYYY-MM-DD
const isoPattern: RegExp = /^\d{4}-\d{2}-\d{2}$/;
if (!isoPattern.test(s)) {
throw new Error("Invalid date format: " + s);
}
const parts: number[] = s.split("-").map(Number);
const year: number = parts[0];
const month: number = parts[1];
const day: number = parts[2];
// Construct a Date in UTC to avoid timezone surprises
const dt: Date = new Date(Date.UTC(year, month - 1, day));
// Validate that the Date object matches the input (detects invalid calendar dates)
if (
dt.getUTCFullYear() !== year ||
dt.getUTCMonth() !== month - 1 ||
dt.getUTCDate() !== day
) {
throw new Error("Invalid calendar date: " + s);
}
return dt;
}
/*
Sort a list of date strings.
Returns a new sorted array; does not mutate the input.
*/
function sortDates(dates: string[]): string[] {
const parsed: Date[] = [];
// Parse all dates; fail fast on invalid input.
for (const s of dates) {
parsed.push(parseDate(s));
}
// Sort using natural Date ordering.
parsed.sort((a: Date, b: Date): number => a.getTime() - b.getTime());
// Convert back to strings.
return parsed.map((d: Date): string => {
const y: number = d.getUTCFullYear();
const m: string = String(d.getUTCMonth() + 1).padStart(2, "0");
const dd: string = String(d.getUTCDate()).padStart(2, "0");
return `${y}-${m}-${dd}`;
});
}
/*
Helper to print a list of strings.
*/
function printList(list: string[]): void {
for (const s of list) {
console.log(" " + s);
}
}
/*
Helper to run a named test case.
*/
function runTest(name: string, dates: string[]): void {
console.log("\n=== " + name + " ===");
try {
const sorted: string[] = sortDates(dates);
printList(sorted);
} catch (e: unknown) {
const msg: string =
e instanceof Error ? e.message : "Unknown error";
console.log("Error: " + msg);
}
}
/*
Main program with multiple test cases.
*/
console.log("TypeScript Date Sorting Demo");
/* Basic chronological order */
runTest("Basic chronological order", [
"2024-01-05",
"2023-12-31",
"2024-01-01",
"2022-07-15"
]);
/* Already sorted input */
runTest("Already sorted input", [
"2020-01-01",
"2020-01-02",
"2020-01-03"
]);
/* Leap year edge cases */
runTest("Leap year edge cases", [
"2020-02-29",
"2019-02-28",
"2021-03-01"
]);
/* Invalid date detection */
runTest("Invalid date detection", [
"2024-13-01", // invalid month
"2024-02-30", // invalid day
"not-a-date" // malformed
]);
/*
run:
TypeScript Date Sorting Demo
=== Basic chronological order ===
2022-07-15
2023-12-31
2024-01-01
2024-01-05
=== Already sorted input ===
2020-01-01
2020-01-02
2020-01-03
=== Leap year edge cases ===
2019-02-28
2020-02-29
2021-03-01
=== Invalid date detection ===
Error: Invalid calendar date: 2024-13-01
*/