datemapper
Version:
A lightweight date utility for format conversion, validation, and date manipulation.
73 lines (62 loc) • 2.63 kB
text/typescript
import * as moment from "moment-timezone"; // Import moment-timezone for timezone handling
/**
* Custom error class for invalid date inputs.
* This improves error handling clarity compared to a generic `Error`.
*/
class DateValidationError extends Error {
constructor(message: string) {
super(message);
this.name = "DateValidationError";
}
}
/**
* Interface defining the structure of the date validation input.
*/
interface DateRangeInput {
from?: string; // Optional start date string
to?: string; // Optional end date string
}
/**
* Validates and normalizes date range inputs while applying timezone adjustments.
*
* - Ensures that the input dates are in a valid format.
* - Converts dates to the beginning (`from`) and end (`to`) of the day.
* - Ensures that `from` is not later than `to`.
* - Applies timezone adjustments to align with the provided timezone.
* - Provides default values if `from` or `to` is missing.
* - Supports customizable date format (defaults to `"YYYY-MM-DD"`).
*
* @param range - An object containing `from` and `to` date strings.
* @param timezone - The timezone to apply (default: UTC).
* @param format - The expected date format (default: "YYYY-MM-DD").
* @returns An object containing normalized `from` and `to` Date objects.
* @throws {DateValidationError} If the provided dates are invalid or incorrectly ordered.
*/
const validateDate = (
range: DateRangeInput,
timezone: string = "UTC",
format: string = "YYYY-MM-DD"
) => {
const { from, to } = range; // Extract `from` and `to` from input
// Validate that `from` and `to` match the expected format
if (from && !moment.tz(from, format, timezone).isValid()) {
throw new DateValidationError(`Invalid starting date format. Expected format: ${format}.`);
}
if (to && !moment.tz(to, format, timezone).isValid()) {
throw new DateValidationError(`Invalid ending date format. Expected format: ${format}.`);
}
// Parse and normalize `from` date (default: 1 month ago)
const fromDate = from
? moment.tz(from, format, timezone).startOf("day").toDate()
: moment.tz(to, format, timezone).subtract(1, "months").startOf("day").toDate();
// Parse and normalize `to` date (default: today)
const toDate = to
? moment.tz(to, format, timezone).endOf("day").toDate()
: moment.tz(fromDate, timezone).endOf("day").toDate();
// Ensure that `from` is not greater than `to`
if (fromDate > toDate) {
throw new DateValidationError("Starting date cannot be later than the ending date.");
}
return { from: fromDate, to: toDate };
};
export default validateDate;