File size: 2,541 Bytes
c09f67c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | import * as chrono from "chrono-node";
import { format } from "date-fns";
/**
* Validates if a date is actually valid (handles month lengths and leap years).
* Creates a Date object and verifies the components match what was requested.
*/
function isValidDate(year: number, month: number, day: number): boolean {
const date = new Date(year, month - 1, day);
return (
date.getFullYear() === year &&
date.getMonth() === month - 1 &&
date.getDate() === day
);
}
/**
* Formats a date string into YYYY-MM-DD format.
* For ISO-format dates (YYYY-MM-DD...), extracts the date portion directly to preserve
* the date in the original timezone (avoids UTC conversion shifting the date).
* Falls back to chrono-node for other formats.
*/
export function formatDate(dateString: string): string | undefined {
if (!dateString?.trim()) return undefined;
const trimmed = dateString.trim();
// Fast path: extract date directly from ISO-like formats (YYYY-MM-DD...)
// This preserves the date in the source timezone instead of converting to UTC
const isoMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})/);
if (isoMatch) {
const [, year, month, day] = isoMatch;
const y = Number(year);
const m = Number(month);
const d = Number(day);
// Validate the date is actually valid (handles month lengths and leap years)
if (isValidDate(y, m, d)) {
return `${year}-${month}-${day}`;
}
// Invalid ISO-format date (e.g., Feb 30), return undefined
return undefined;
}
// Fallback: use chrono-node for other formats (Oct 1, 2025, 01/10/2025, etc.)
const parsed = chrono.parseDate(trimmed);
if (!parsed) return undefined;
return format(parsed, "yyyy-MM-dd");
}
export function formatAmountValue({
amount,
inverted,
}: {
amount: string;
inverted?: boolean;
}) {
let value: number;
// Handle special minus sign (−) by replacing with standard minus (-)
const normalizedAmount = amount.replace(/−/g, "-");
if (normalizedAmount.includes(",")) {
// Remove thousands separators and replace the comma with a period.
value = +normalizedAmount.replace(/\./g, "").replace(",", ".");
} else if (normalizedAmount.match(/\.\d{2}$/)) {
// If it ends with .XX, it's likely a decimal; remove internal periods.
value = +normalizedAmount.replace(/\.(?=\d{3})/g, "");
} else {
// If neither condition is met, convert the amount directly to a number
value = +normalizedAmount;
}
if (inverted) {
return +(value * -1);
}
return value;
}
|