UNPKG

@wojtekmaj/date-utils

Version:

A collection of date-related utilities.

559 lines (558 loc) 17.4 kB
/** * Utils */ function makeGetEdgeOfNeighbor(getPeriod, getEdgeOfPeriod, defaultOffset) { return function makeGetEdgeOfNeighborInternal(date, offset = defaultOffset) { const previousPeriod = getPeriod(date) + offset; return getEdgeOfPeriod(previousPeriod); }; } function makeGetEnd(getBeginOfNextPeriod) { return function makeGetEndInternal(date) { return new Date(getBeginOfNextPeriod(date).getTime() - 1); }; } function makeGetRange(getStart, getEnd) { return function makeGetRangeInternal(date) { return [getStart(date), getEnd(date)]; }; } /** * Simple getters - getting a property of a given point in time */ /** * Gets year from a given date. * * @param {DateLike} date Date to get year from * @returns {number} Year */ export function getYear(date) { if (date instanceof Date) { return date.getFullYear(); } if (typeof date === 'number') { return date; } const year = Number.parseInt(date, 10); if (typeof date === 'string' && !Number.isNaN(year)) { return year; } throw new Error(`Failed to get year from date: ${date}.`); } /** * Gets month from a given date. * * @param {Date} date Date to get month from * @returns {number} Month */ export function getMonth(date) { if (date instanceof Date) { return date.getMonth(); } throw new Error(`Failed to get month from date: ${date}.`); } /** * Gets human-readable month from a given date. * * @param {Date} date Date to get human-readable month from * @returns {number} Human-readable month */ export function getMonthHuman(date) { if (date instanceof Date) { return date.getMonth() + 1; } throw new Error(`Failed to get human-readable month from date: ${date}.`); } /** * Gets day of the month from a given date. * * @param {Date} date Date to get day of the month from * @returns {number} Day of the month */ export function getDate(date) { if (date instanceof Date) { return date.getDate(); } throw new Error(`Failed to get year from date: ${date}.`); } /** * Gets hours from a given date. * * @param {Date | string} date Date to get hours from * @returns {number} Hours */ export function getHours(date) { if (date instanceof Date) { return date.getHours(); } if (typeof date === 'string') { const datePieces = date.split(':'); if (datePieces.length >= 2) { const hoursString = datePieces[0]; if (hoursString) { const hours = Number.parseInt(hoursString, 10); if (!Number.isNaN(hours)) { return hours; } } } } throw new Error(`Failed to get hours from date: ${date}.`); } /** * Gets minutes from a given date. * * @param {Date | string} date Date to get minutes from * @returns {number} Minutes */ export function getMinutes(date) { if (date instanceof Date) { return date.getMinutes(); } if (typeof date === 'string') { const datePieces = date.split(':'); if (datePieces.length >= 2) { const minutesString = datePieces[1] || '0'; const minutes = Number.parseInt(minutesString, 10); if (!Number.isNaN(minutes)) { return minutes; } } } throw new Error(`Failed to get minutes from date: ${date}.`); } /** * Gets seconds from a given date. * * @param {Date | string} date Date to get seconds from * @returns {number} Seconds */ export function getSeconds(date) { if (date instanceof Date) { return date.getSeconds(); } if (typeof date === 'string') { const datePieces = date.split(':'); if (datePieces.length >= 2) { const secondsWithMillisecondsString = datePieces[2] || '0'; const seconds = Number.parseInt(secondsWithMillisecondsString, 10); if (!Number.isNaN(seconds)) { return seconds; } } } throw new Error(`Failed to get seconds from date: ${date}.`); } /** * Gets milliseconds from a given date. * * @param {Date | string} date Date to get milliseconds from * @returns {number} Milliseconds */ export function getMilliseconds(date) { if (date instanceof Date) { return date.getMilliseconds(); } if (typeof date === 'string') { const datePieces = date.split(':'); if (datePieces.length >= 2) { const secondsWithMillisecondsString = datePieces[2] || '0'; const millisecondsString = secondsWithMillisecondsString.split('.')[1] || '0'; const milliseconds = Number.parseInt(millisecondsString, 10); if (!Number.isNaN(milliseconds)) { return milliseconds; } } } throw new Error(`Failed to get seconds from date: ${date}.`); } /** * Century */ /** * Gets century start date from a given date. * * @param {DateLike} date Date to get century start from * @returns {Date} Century start date */ export function getCenturyStart(date) { const year = getYear(date); const centuryStartYear = year + ((-year + 1) % 100); const centuryStartDate = new Date(); centuryStartDate.setFullYear(centuryStartYear, 0, 1); centuryStartDate.setHours(0, 0, 0, 0); return centuryStartDate; } /** * Gets previous century start date from a given date. * * @param {DateLike} date Date to get previous century start from * @returns {Date} Previous century start date */ export const getPreviousCenturyStart = makeGetEdgeOfNeighbor(getYear, getCenturyStart, -100); /** * Gets next century start date from a given date. * * @param {DateLike} date Date to get next century start from * @returns {Date} Next century start date */ export const getNextCenturyStart = makeGetEdgeOfNeighbor(getYear, getCenturyStart, 100); /** * Gets century end date from a given date. * * @param {DateLike} date Date to get century end from * @returns {Date} Century end date */ export const getCenturyEnd = makeGetEnd(getNextCenturyStart); /** * Gets previous century end date from a given date. * * @param {DateLike} date Date to get previous century end from * @returns {Date} Previous century end date */ export const getPreviousCenturyEnd = makeGetEdgeOfNeighbor(getYear, getCenturyEnd, -100); /** * Gets next century end date from a given date. * * @param {DateLike} date Date to get next century end from * @returns {Date} Next century end date */ export const getNextCenturyEnd = makeGetEdgeOfNeighbor(getYear, getCenturyEnd, 100); /** * Gets century start and end dates from a given date. * * @param {DateLike} date Date to get century start and end from * @returns {[Date, Date]} Century start and end dates */ export const getCenturyRange = makeGetRange(getCenturyStart, getCenturyEnd); /** * Decade */ /** * Gets decade start date from a given date. * * @param {DateLike} date Date to get decade start from * @returns {Date} Decade start date */ export function getDecadeStart(date) { const year = getYear(date); const decadeStartYear = year + ((-year + 1) % 10); const decadeStartDate = new Date(); decadeStartDate.setFullYear(decadeStartYear, 0, 1); decadeStartDate.setHours(0, 0, 0, 0); return decadeStartDate; } /** * Gets previous decade start date from a given date. * * @param {DateLike} date Date to get previous decade start from * @returns {Date} Previous decade start date */ export const getPreviousDecadeStart = makeGetEdgeOfNeighbor(getYear, getDecadeStart, -10); /** * Gets next decade start date from a given date. * * @param {DateLike} date Date to get next decade start from * @returns {Date} Next decade start date */ export const getNextDecadeStart = makeGetEdgeOfNeighbor(getYear, getDecadeStart, 10); /** * Gets decade end date from a given date. * * @param {DateLike} date Date to get decade end from * @returns {Date} Decade end date */ export const getDecadeEnd = makeGetEnd(getNextDecadeStart); /** * Gets previous decade end date from a given date. * * @param {DateLike} date Date to get previous decade end from * @returns {Date} Previous decade end date */ export const getPreviousDecadeEnd = makeGetEdgeOfNeighbor(getYear, getDecadeEnd, -10); /** * Gets next decade end date from a given date. * * @param {DateLike} date Date to get next decade end from * @returns {Date} Next decade end date */ export const getNextDecadeEnd = makeGetEdgeOfNeighbor(getYear, getDecadeEnd, 10); /** * Gets decade start and end dates from a given date. * * @param {DateLike} date Date to get decade start and end from * @returns {[Date, Date]} Decade start and end dates */ export const getDecadeRange = makeGetRange(getDecadeStart, getDecadeEnd); /** * Year */ /** * Gets year start date from a given date. * * @param {DateLike} date Date to get year start from * @returns {Date} Year start date */ export function getYearStart(date) { const year = getYear(date); const yearStartDate = new Date(); yearStartDate.setFullYear(year, 0, 1); yearStartDate.setHours(0, 0, 0, 0); return yearStartDate; } /** * Gets previous year start date from a given date. * * @param {DateLike} date Date to get previous year start from * @returns {Date} Previous year start date */ export const getPreviousYearStart = makeGetEdgeOfNeighbor(getYear, getYearStart, -1); /** * Gets next year start date from a given date. * * @param {DateLike} date Date to get next year start from * @returns {Date} Next year start date */ export const getNextYearStart = makeGetEdgeOfNeighbor(getYear, getYearStart, 1); /** * Gets year end date from a given date. * * @param {DateLike} date Date to get year end from * @returns {Date} Year end date */ export const getYearEnd = makeGetEnd(getNextYearStart); /** * Gets previous year end date from a given date. * * @param {DateLike} date Date to get previous year end from * @returns {Date} Previous year end date */ export const getPreviousYearEnd = makeGetEdgeOfNeighbor(getYear, getYearEnd, -1); /** * Gets next year end date from a given date. * * @param {DateLike} date Date to get next year end from * @returns {Date} Next year end date */ export const getNextYearEnd = makeGetEdgeOfNeighbor(getYear, getYearEnd, 1); /** * Gets year start and end dates from a given date. * * @param {DateLike} date Date to get year start and end from * @returns {[Date, Date]} Year start and end dates */ export const getYearRange = makeGetRange(getYearStart, getYearEnd); /** * Month */ function makeGetEdgeOfNeighborMonth(getEdgeOfPeriod, defaultOffset) { return function makeGetEdgeOfNeighborMonthInternal(date, offset = defaultOffset) { const year = getYear(date); const month = getMonth(date) + offset; const previousPeriod = new Date(); previousPeriod.setFullYear(year, month, 1); previousPeriod.setHours(0, 0, 0, 0); return getEdgeOfPeriod(previousPeriod); }; } /** * Gets month start date from a given date. * * @param {DateLike} date Date to get month start from * @returns {Date} Month start date */ export function getMonthStart(date) { const year = getYear(date); const month = getMonth(date); const monthStartDate = new Date(); monthStartDate.setFullYear(year, month, 1); monthStartDate.setHours(0, 0, 0, 0); return monthStartDate; } /** * Gets previous month start date from a given date. * * @param {Date} date Date to get previous month start from * @returns {Date} Previous month start date */ export const getPreviousMonthStart = makeGetEdgeOfNeighborMonth(getMonthStart, -1); /** * Gets next month start date from a given date. * * @param {Date} date Date to get next month start from * @returns {Date} Next month start date */ export const getNextMonthStart = makeGetEdgeOfNeighborMonth(getMonthStart, 1); /** * Gets month end date from a given date. * * @param {Date} date Date to get month end from * @returns {Date} Month end date */ export const getMonthEnd = makeGetEnd(getNextMonthStart); /** * Gets previous month end date from a given date. * * @param {Date} date Date to get previous month end from * @returns {Date} Previous month end date */ export const getPreviousMonthEnd = makeGetEdgeOfNeighborMonth(getMonthEnd, -1); /** * Gets next month end date from a given date. * * @param {Date} date Date to get next month end from * @returns {Date} Next month end date */ export const getNextMonthEnd = makeGetEdgeOfNeighborMonth(getMonthEnd, 1); /** * Gets month start and end dates from a given date. * * @param {Date} date Date to get month start and end from * @returns {[Date, Date]} Month start and end dates */ export const getMonthRange = makeGetRange(getMonthStart, getMonthEnd); /** * Day */ function makeGetEdgeOfNeighborDay(getEdgeOfPeriod, defaultOffset) { return function makeGetEdgeOfNeighborDayInternal(date, offset = defaultOffset) { const year = getYear(date); const month = getMonth(date); const day = getDate(date) + offset; const previousPeriod = new Date(); previousPeriod.setFullYear(year, month, day); previousPeriod.setHours(0, 0, 0, 0); return getEdgeOfPeriod(previousPeriod); }; } /** * Gets day start date from a given date. * * @param {DateLike} date Date to get day start from * @returns {Date} Day start date */ export function getDayStart(date) { const year = getYear(date); const month = getMonth(date); const day = getDate(date); const dayStartDate = new Date(); dayStartDate.setFullYear(year, month, day); dayStartDate.setHours(0, 0, 0, 0); return dayStartDate; } /** * Gets previous day start date from a given date. * * @param {Date} date Date to get previous day start from * @returns {Date} Previous day start date */ export const getPreviousDayStart = makeGetEdgeOfNeighborDay(getDayStart, -1); /** * Gets next day start date from a given date. * * @param {Date} date Date to get next day start from * @returns {Date} Next day start date */ export const getNextDayStart = makeGetEdgeOfNeighborDay(getDayStart, 1); /** * Gets day end date from a given date. * * @param {Date} date Date to get day end from * @returns {Date} Day end date */ export const getDayEnd = makeGetEnd(getNextDayStart); /** * Gets previous day end date from a given date. * * @param {DateLike} date Date to get previous day end from * @returns {Date} Previous day end date */ export const getPreviousDayEnd = makeGetEdgeOfNeighborDay(getDayEnd, -1); /** * Gets next day end date from a given date. * * @param {DateLike} date Date to get next day end from * @returns {Date} Next day end date */ export const getNextDayEnd = makeGetEdgeOfNeighborDay(getDayEnd, 1); /** * Gets day start and end dates from a given date. * * @param {DateLike} date Date to get day start and end from * @returns {[Date, Date]} Day start and end dates */ export const getDayRange = makeGetRange(getDayStart, getDayEnd); /** * Other */ /** * Returns a number of days in a month of a given date. * * @param {Date} date Date * @returns {number} Number of days in a month */ export function getDaysInMonth(date) { return getDate(getMonthEnd(date)); } function padStart(num, val = 2) { const numStr = `${num}`; if (numStr.length >= val) { return num; } return `0000${numStr}`.slice(-val); } /** * Returns local hours and minutes (hh:mm). * * @param {Date | string} date Date to get hours and minutes from * @returns {string} Local hours and minutes */ export function getHoursMinutes(date) { const hours = padStart(getHours(date)); const minutes = padStart(getMinutes(date)); return `${hours}:${minutes}`; } /** * Returns local hours, minutes and seconds (hh:mm:ss). * * @param {Date | string} date Date to get hours, minutes and seconds from * @returns {string} Local hours, minutes and seconds */ export function getHoursMinutesSeconds(date) { const hours = padStart(getHours(date)); const minutes = padStart(getMinutes(date)); const seconds = padStart(getSeconds(date)); return `${hours}:${minutes}:${seconds}`; } /** * Returns local month in ISO-like format (YYYY-MM). * * @param {Date} date Date to get month in ISO-like format from * @returns {string} Local month in ISO-like format */ export function getISOLocalMonth(date) { const year = padStart(getYear(date), 4); const month = padStart(getMonthHuman(date)); return `${year}-${month}`; } /** * Returns local date in ISO-like format (YYYY-MM-DD). * * @param {Date} date Date to get date in ISO-like format from * @returns {string} Local date in ISO-like format */ export function getISOLocalDate(date) { const year = padStart(getYear(date), 4); const month = padStart(getMonthHuman(date)); const day = padStart(getDate(date)); return `${year}-${month}-${day}`; } /** * Returns local date & time in ISO-like format (YYYY-MM-DDThh:mm:ss). * * @param {Date} date Date to get date & time in ISO-like format from * @returns {string} Local date & time in ISO-like format */ export function getISOLocalDateTime(date) { return `${getISOLocalDate(date)}T${getHoursMinutesSeconds(date)}`; }