Files
crowd-fund-web/src/utils/dates.ts
T

98 lines
3.0 KiB
TypeScript

import type { Locale } from "../i18n/locales";
export function formatDate(date: Date, locale: Locale) {
const options: Intl.DateTimeFormatOptions = {
day: "2-digit",
month: "short",
year: "numeric",
};
return date.toLocaleDateString(locale, options);
}
/**
* The first instant of the day for the given date (midnight, 00:00).
* @param date The date to normalize
* @returns A new Date set to the start of the given day
*/
export function startOfDay(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
/**
* The last instant of the day for the given date (23:59:59.999).
* Derived from the start of the following day rather than hardcoding the end-of-day time.
* @param date The date to normalize
* @returns A new Date set to the end of the given day
*/
export function endOfDay(date: Date): Date {
// Start of the next day, minus a single millisecond
const nextDay = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
return new Date(nextDay.getTime() - 1);
}
/**
* Get a date `n` ms from now
* @param offset Milliseconds since now until future date
* @returns {Date}
*/
export function getDateInFuture(offset: number): Date {
const now = new Date();
now.setTime(now.getTime() + offset);
return now;
}
/**
* Parses an ISO-like date string. Replaces partial values and wildcards `*` with the appropriate current value.
* @param raw
* @param now
* @returns
*/
export function parseDate(raw: string | undefined, now: Date = new Date()): Date | undefined {
if (!raw) return undefined;
const parts = raw.split("-");
if (
parts.length < 1 ||
parts.length > 3 ||
!/^(?:\d{4}|\*)$/.test(parts[0]) ||
parts.slice(1).some((part) => !/^(?:\d{2}|\*)$/.test(part))
) {
console.warn(`Invalid value: ${raw}`);
return undefined;
}
const year = parts[0] === "*" ? now.getFullYear() : Number(parts[0]);
const month =
parts[1] === undefined || parts[1] === "*" ? now.getMonth() + 1 : Number(parts[1]);
const day = parts[2] === undefined || parts[2] === "*" ? now.getDate() : Number(parts[2]);
return new Date(year, month - 1, day);
}
/**
* Latest date a project may start its campaign, as configured by the platform owner.
* Calculated from `PUBLIC_CAMPAIGN_MAX_END_DATE`. Leave empty to disable the limit.
*/
export const CAMPAIGN_MAX_END_DATE = parseDate(import.meta.env.PUBLIC_CAMPAIGN_MAX_END_DATE);
function getMinStartDate() {
const minStartDate = getDateInFuture(
86400000 * parseInt(import.meta.env.PUBLIC_CAMPAIGN_MIN_REV_DAYS || 1),
);
minStartDate.setHours(0, 0, 0);
return minStartDate;
}
/**
* Earliest date a project may start its campaign, as calculated from the platform's minimum review days.
* Calculated from `PUBLIC_CAMPAIGN_MIN_REV_DAYS`. When empty will default to 1 day from now.
*/
export const CAMPAIGN_MIN_START_DATE = getMinStartDate();