Skip to main content
Home
Works with
This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
This package works with Browsers
JSR Score100%
Downloads53/wk
Published10 months ago (0.1.3)

small date utilities

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
/** * represents a day of the week as a numeric value (0 = Sunday, 6 = Saturday). */ export type DayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6; /** * returns the Unix timestamp in milliseconds for a given date. * @param date the date to convert. * @returns the Unix timestamp in milliseconds. */ /*#__NO_SIDE_EFFECTS__*/ export const toUnixMilliseconds = (date: Date): number => { return date.getTime(); }; /** * returns the Unix timestamp in seconds for a given date * @param date the date to convert. * @returns the Unix timestamp in seconds. */ /*#__NO_SIDE_EFFECTS__*/ export const toUnixSeconds = (date: Date): number => { return Math.floor(toUnixMilliseconds(date) / 1_000); }; /** * converts a date to an ISO 8601 date string (YYYY-MM-DD) in local timezone * @param date the date to format * @returns the formatted date string */ /*#__NO_SIDE_EFFECTS__*/ export const toISODateString = (date: Date): string => { return date.toLocaleDateString('sv-SE'); }; /** * converts a date to an ISO 8601 datetime string (YYYY-MM-DDTHH:mm:ss.sss) in local timezone * @param date the date to format * @returns the formatted datetime string */ /*#__NO_SIDE_EFFECTS__*/ export const toISODateTimeString = (date: Date): string => { return date.toLocaleString('sv-SE').replace(' ', 'T') + '.' + ('' + getMilliseconds(date)).padStart(3, '0'); }; /** * returns the milliseconds portion of a given date. * @param date the date to extract from. * @returns the milliseconds portion of the date. */ /*#__NO_SIDE_EFFECTS__*/ export const getMilliseconds = (date: Date): number => { return date.getMilliseconds(); }; /** * returns the seconds portion of a given date. * @param date the date to extract from. * @returns the seconds portion of the date. */ /*#__NO_SIDE_EFFECTS__*/ export const getSeconds = (date: Date): number => { return date.getSeconds(); }; /** * returns the minutes portion of a given date. * @param date the date to extract from. * @returns the minutes portion of the date. */ /*#__NO_SIDE_EFFECTS__*/ export const getMinutes = (date: Date): number => { return date.getMinutes(); }; /** * returns the hours portion of a given date. * @param date the date to extract from. * @returns the hours portion of the date. */ /*#__NO_SIDE_EFFECTS__*/ export const getHours = (date: Date): number => { return date.getHours(); }; /** * returns the day of the week for a given date (0 = Sunday, 6 = Saturday). * @param date the date to extract from. * @returns the day of the week as a number. */ /*#__NO_SIDE_EFFECTS__*/ export const getDayOfWeek = (date: Date): DayOfWeek => { return date.getDay() as DayOfWeek; }; /** * returns the day of the month for a given date. * @param date the date to extract from. * @returns the day of the month as a number. */ /*#__NO_SIDE_EFFECTS__*/ export const getDayOfMonth = (date: Date): number => { return date.getDate(); }; /** * returns the month portion of a given date (0 = January, 11 = December). * @param date the date to extract from. * @returns the month as a number. */ /*#__NO_SIDE_EFFECTS__*/ export const getMonth = (date: Date): number => { return date.getMonth(); }; /** * returns the year portion of a given date. * @param date the date to extract from. * @returns the year as a number. */ /*#__NO_SIDE_EFFECTS__*/ export const getYear = (date: Date): number => { return date.getFullYear(); }; /** * compares two dates and returns a number indicating their relative order, * in UTC time. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns -1 if a is before b, 1 if a is after b, or 0 if they are equal. */ /*#__NO_SIDE_EFFECTS__*/ export const compareUtcAsc = <TDate extends Date>(a: TDate, b: TDate): number => { const aMs = toUnixMilliseconds(a); const bMs = toUnixMilliseconds(b); if (aMs < bMs) { return -1; } if (aMs > bMs) { return 1; } return 0; }; /** * compares two dates and returns a number indicating their relative order, * in local time. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns -1 if a is before b, 1 if a is after b, or 0 if they are equal. */ /*#__NO_SIDE_EFFECTS__*/ export const compareLocalAsc = <TDate extends Date>(a: TDate, b: TDate): number => { const diff = getMilliseconds(a) - getMilliseconds(b) || getSeconds(a) - getSeconds(b) || getMinutes(a) - getMinutes(b) || getHours(a) - getHours(b) || getDayOfMonth(a) - getDayOfMonth(b) || getMonth(a) - getMonth(b) || getYear(a) - getYear(b); if (diff < 0) { return -1; } if (diff > 0) { return 1; } return 0; }; /** * checks if a date is before another date. * @template TDate * @param a the date to compare. * @param b the date to compare against. * @returns true if first date is before the second, false otherwise. */ /*#__NO_SIDE_EFFECTS__*/ export const isBeforeDate = <TDate extends Date>(a: TDate, b: TDate): boolean => { return a !== b && toUnixMilliseconds(a) < toUnixMilliseconds(b); }; /** * checks if a date is after another date. * @template TDate * @param a the date to compare. * @param b the date to compare against. * @returns true if the first date is after the second, false otherwise. */ /*#__NO_SIDE_EFFECTS__*/ export const isAfterDate = <TDate extends Date>(a: TDate, b: TDate): boolean => { return a !== b && toUnixMilliseconds(a) > toUnixMilliseconds(b); }; /** * checks if two dates are exactly the same. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns true if the two dates are the same, false otherwise. */ /*#__NO_SIDE_EFFECTS__*/ export const isSameDate = <TDate extends Date>(a: TDate, b: TDate): boolean => { return a === b || toUnixMilliseconds(a) === toUnixMilliseconds(b); }; /** * checks if two dates fall on the same calendar day. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns true if the two dates fall on the same calendar day, false otherwise. */ /*#__NO_SIDE_EFFECTS__*/ export const isSameCalendarDate = <TDate extends Date>(a: TDate, b: TDate): boolean => { if (a === b) { return true; } return ( getDayOfMonth(a) === getDayOfMonth(b) && getMonth(a) === getMonth(b) && getYear(a) === getYear(b) ); }; /** * checks if two dates fall in the same calendar month. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns true if the two dates are in the same month, false otherwise. */ /*#__NO_SIDE_EFFECTS__*/ export const isSameCalendarMonth = <TDate extends Date>(a: TDate, b: TDate): boolean => { if (a === b) { return true; } return ( getMonth(a) === getMonth(b) && getYear(a) === getYear(b) ); }; /** * checks if two dates fall in the same calendar year. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns true if the two dates are in the same year, false otherwise. */ /*#__NO_SIDE_EFFECTS__*/ export const isSameCalendarYear = <TDate extends Date>(a: TDate, b: TDate): boolean => { if (a === b) { return true; } return getYear(a) === getYear(b); }; /** * returns the earlier of two dates. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns the earlier of the two dates. */ /*#__NO_SIDE_EFFECTS__*/ export const min = <TDate extends Date>(a: TDate, b: TDate): TDate => { return isBeforeDate(a, b) ? a : b; }; /** * returns the later of two dates. * @template TDate * @param a the first date to compare. * @param b the second date to compare. * @returns the later of the two dates. */ /*#__NO_SIDE_EFFECTS__*/ export const max = <TDate extends Date>(a: TDate, b: TDate): TDate => { return isAfterDate(a, b) ? a : b; }; /** * clamps a date between a minimum and maximum range. * @template TDate * @param date the date to clamp. * @param min the minimum allowable date. * @param max the maximum allowable date. * @returns the clamped date. */ /*#__NO_SIDE_EFFECTS__*/ export const clamp = <TDate extends Date>( date: TDate, min: TDate | undefined, max: TDate | undefined, ): TDate => { if (min !== undefined && isBeforeDate(date, min)) { return min; } if (max !== undefined && isAfterDate(date, max)) { return max; } return date; }; /** * calculates the difference in milliseconds between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in milliseconds. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInMilliseconds = <TDate extends Date>(a: TDate, b: TDate): number => { return toUnixMilliseconds(a) - toUnixMilliseconds(b); }; /** * calculates the difference in seconds between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in seconds. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInSeconds = <TDate extends Date>(a: TDate, b: TDate): number => { return Math.trunc(differenceInMilliseconds(a, b) / 1_000); }; /** * calculates the difference in minutes between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in minutes. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInMinutes = <TDate extends Date>(a: TDate, b: TDate): number => { return Math.trunc(differenceInMilliseconds(a, b) / 60_000); }; /** * calculates the difference in hours between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in hours. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInHours = <TDate extends Date>(a: TDate, b: TDate): number => { return Math.trunc(differenceInMilliseconds(a, b) / 3_600_000); }; /** * calculates the difference in days between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in days. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInDays = <TDate extends Date>(a: TDate, b: TDate): number => { return Math.trunc(differenceInMilliseconds(a, b) / 86_400_000); }; /** * calculates the difference in calendar days between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in calendar days. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInCalendarDays = <TDate extends Date>(a: TDate, b: TDate): number => { return differenceInDays(startOfDay(a), startOfDay(b)); }; /** * calculates the difference in weeks between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in weeks. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInWeeks = <TDate extends Date>(a: TDate, b: TDate): number => { return Math.trunc(differenceInDays(a, b) / 7); }; /** * calculates the difference in calendar weeks between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in calendar weeks. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInCalendarWeeks = <TDate extends Date>(a: TDate, b: TDate): number => { return differenceInWeeks(startOfWeek(a), startOfWeek(b)); }; /** * calculates the difference in months between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in months. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInMonths = <TDate extends Date>(a: TDate, b: TDate): number => { return (getYear(a) - getYear(b)) * 12 + (getMonth(a) - getMonth(b)); }; /** * calculates the difference in calendar months between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in calendar months. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInCalendarMonths = <TDate extends Date>(a: TDate, b: TDate): number => { return differenceInMonths(startOfMonth(a), startOfMonth(b)); }; /** * calculates the difference in years between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in years. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInYears = <TDate extends Date>(a: TDate, b: TDate): number => { return getYear(a) - getYear(b); }; /** * calculates the difference in calendar years between two dates. * @template TDate * @param a the first date. * @param b the second date. * @returns the difference in calendar years. */ /*#__NO_SIDE_EFFECTS__*/ export const differenceInCalendarYears = <TDate extends Date>(a: TDate, b: TDate): number => { return differenceInYears(startOfYear(a), startOfYear(b)); }; type DateConstructor<TDate extends Date> = { new (value: number | string | TDate): TDate }; /** * creates a copy of a given date. * @template TDate * @param date the date to clone. * @returns a new date object with the same value as the input date. */ /*#__NO_SIDE_EFFECTS__*/ export const cloneDate = <TDate extends Date>(date: TDate): TDate => { return new (date.constructor as DateConstructor<TDate>)(date); }; /** * returns the start of the day for a given date. * @template TDate * @param date the date to find the start of the day for. * @returns a new date set to the start of the day. */ /*#__NO_SIDE_EFFECTS__*/ export const startOfDay = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setHours(0, 0, 0, 0); return d; }; /** * returns the end of the day for a given date. * @template TDate * @param date the date to find the end of the day for. * @returns a new date set to the end of the day. */ /*#__NO_SIDE_EFFECTS__*/ export const endOfDay = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setHours(23, 59, 59, 999); return d; }; /** * returns the start of the week for a given date. * @template TDate * @param date the date to find the start of the week for. * @returns a new date set to the start of the week. */ /*#__NO_SIDE_EFFECTS__*/ export const startOfWeek = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setDate(getDayOfMonth(d) - getDayOfWeek(d)); d.setHours(0, 0, 0, 0); return d; }; /** * returns the end of the week for a given date. * @template TDate * @param date the date to find the end of the week for. * @returns a new date set to the end of the week. */ /*#__NO_SIDE_EFFECTS__*/ export const endOfWeek = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setDate(getDayOfMonth(d) + (6 - getDayOfWeek(d))); d.setHours(23, 59, 59, 999); return d; }; /** * returns the start of the month for a given date. * @template TDate * @param date the date to find the start of the month for. * @returns a new date set to the start of the month. */ /*#__NO_SIDE_EFFECTS__*/ export const startOfMonth = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setDate(1); d.setHours(0, 0, 0, 0); return d; }; /** * returns the end of the month for a given date. * @template TDate * @param date the date to find the end of the month for. * @returns a new date set to the end of the month. */ /*#__NO_SIDE_EFFECTS__*/ export const endOfMonth = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setMonth(getMonth(d) + 1, 0); d.setHours(23, 59, 59, 999); return d; }; /** * returns the start of the year for a given date. * @template TDate * @param date the date to find the start of the year for. * @returns a new date set to the start of the year. */ /*#__NO_SIDE_EFFECTS__*/ export const startOfYear = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setMonth(0, 1); d.setHours(0, 0, 0, 0); return d; }; /** * returns the end of the year for a given date. * @template TDate * @param date the date to find the end of the year for. * @returns a new date set to the end of the year. */ /*#__NO_SIDE_EFFECTS__*/ export const endOfYear = <TDate extends Date>(date: TDate): TDate => { const d = cloneDate(date); d.setMonth(11, 31); d.setHours(23, 59, 59, 999); return d; }; /** * adds a specified number of milliseconds to a date. * @template TDate * @param date the date to add milliseconds to. * @param milliseconds the number of milliseconds to add. * @returns a new date with the added milliseconds. */ /*#__NO_SIDE_EFFECTS__*/ export const addMilliseconds = <TDate extends Date>(date: TDate, milliseconds: number): TDate => { const d = cloneDate(date); d.setMilliseconds(getMilliseconds(d) + milliseconds); return d; }; /** * adds a specified number of seconds to a date. * @template TDate * @param date the date to add seconds to. * @param seconds the number of seconds to add. * @returns a new date with the added seconds. */ /*#__NO_SIDE_EFFECTS__*/ export const addSeconds = <TDate extends Date>(date: TDate, seconds: number): TDate => { const d = cloneDate(date); d.setSeconds(getSeconds(d) + seconds); return d; }; /** * adds a specified number of minutes to a date. * @template TDate * @param date the date to add minutes to. * @param minutes the number of minutes to add. * @returns a new date with the added minutes. */ /*#__NO_SIDE_EFFECTS__*/ export const addMinutes = <TDate extends Date>(date: TDate, minutes: number): TDate => { const d = cloneDate(date); d.setMinutes(getMinutes(d) + minutes); return d; }; /** * adds a specified number of hours to a date. * @template TDate * @param date the date to add hours to. * @param hours the number of hours to add. * @returns a new date with the added hours. */ /*#__NO_SIDE_EFFECTS__*/ export const addHours = <TDate extends Date>(date: TDate, hours: number): TDate => { const d = cloneDate(date); d.setHours(getHours(d) + hours); return d; }; /** * adds a specified number of days to a date. * @template TDate * @param date the date to add days to. * @param days the number of days to add. * @returns a new date with the added days. */ /*#__NO_SIDE_EFFECTS__*/ export const addDays = <TDate extends Date>(date: TDate, days: number): TDate => { const d = cloneDate(date); d.setDate(getDayOfMonth(d) + days); return d; }; /** * adds a specified number of months to a date. * @template TDate * @param date the date to add months to. * @param months the number of months to add. * @returns a new date with the added months. */ /*#__NO_SIDE_EFFECTS__*/ export const addMonths = <TDate extends Date>(date: TDate, months: number): TDate => { const d = cloneDate(date); d.setMonth(getMonth(d) + months); return d; }; /** * adds a specified number of years to a date. * @template TDate * @param date the date to add years to. * @param years the number of years to add. * @returns a new date with the added years. */ /*#__NO_SIDE_EFFECTS__*/ export const addYears = <TDate extends Date>(date: TDate, years: number): TDate => { const d = cloneDate(date); d.setFullYear(getYear(d) + years); return d; }; /** * returns the previous occurrence of a specific day of the week. * @template TDate * @param date the starting date. * @param day the target day of the week. * @returns a new date set to the previous occurrence of the specified day. */ /*#__NO_SIDE_EFFECTS__*/ export const previousDay = <TDate extends Date>(date: TDate, day: DayOfWeek): TDate => { let delta = day - getDayOfWeek(date); if (delta >= 0) { delta -= 7; } return addDays(date, delta); }; /** * returns the next occurrence of a specific day of the week. * @template TDate * @param date the starting date. * @param day the target day of the week. * @returns a new date set to the next occurrence of the specified day. */ /*#__NO_SIDE_EFFECTS__*/ export const nextDay = <TDate extends Date>(date: TDate, day: DayOfWeek): TDate => { let delta = day - getDayOfWeek(date); if (delta <= 0) { delta += 7; } return addDays(date, delta); };