UNPKG

@devexperts/dxcharts-lite

Version:
193 lines (192 loc) 7.67 kB
/* * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { eachDayOfInterval, isSameDay, isMonday, isTuesday, isWednesday, isThursday, isFriday, isSaturday, isSunday, startOfMonth, endOfMonth, } from 'date-fns'; /** * Factory that return a {@link TimeFormatMatcher} function for a given {@link ParsedTimeFormats} * @see * Detailed explanation you can find here {@link TimeFormatMatcher} */ export const timeFormatMatcherFactory = (timeFormat) => { switch (timeFormat.key) { case 'lessThanSecond': return lessThanSecondMatcherFactory(timeFormat); case 'month': return monthMatcherFactory(timeFormat); case 'second': case 'minute': case 'hour': case 'day': case 'year': return commonMatcherFactory(timeFormat); case 'week-weekday': return weekWeekdayMatcherFactory(timeFormat); default: return () => false; } }; /** * Returns a `number` for a given {@link Date} and {@link TimeFormat} * @example * const date = new Date('Fri Feb 14 2023 14:50:10 GMT+0500'); * const timeFormat: TimeFormat = 'day'; * // `getTimeFromDateByTimeFormat` will return days from given date and it will be 14, because `Feb 14` * const days = getTimeFromDateByTimeFormat(date, timeFormat); // 14 */ const getTimeFromDateByTimeFormat = (date, timeFormat) => { switch (timeFormat) { case 'lessThanSecond': return date.getMilliseconds(); case 'month': return date.getMonth(); case 'second': return date.getSeconds(); case 'minute': return date.getMinutes(); case 'hour': return date.getHours(); case 'day': return date.getDate(); case 'year': return date.getFullYear(); case 'week-weekday': return date.getDate(); } }; /** * Checks if the given dates are not the same for a given {@link TimeFormat} * @example * const date1 = new Date('Fri Feb 10 2023 14:50:10 GMT+0500'); * const date2 = new Date('Fri Feb 09 2023 14:50:10 GMT+0500'); * const timeFormat: TimeFormat = 'day'; * // `true` because it takes days from `Feb 10` and `Feb 09`, and 10 !== 9 * const notTheSame = datesNOTtheSame(timeFormat)(date1, date2); // true * */ const datesNOTtheSame = (key) => (currentDate, prevDate) => { const currentTime = getTimeFromDateByTimeFormat(currentDate, key); const prevTime = getTimeFromDateByTimeFormat(prevDate, key); return currentTime !== prevTime; }; /** * Checks if the given dates are are bigger or equal for a given {@link TimeFormat} * @example * const date1 = new Date('Fri Feb 10 2023 14:50:10 GMT+0500'); * const date2 = new Date('Fri Feb 10 2023 14:50:10 GMT+0500'); * const timeFormat: TimeFormat = 'day'; * // `true` because it takes days from `Feb 10` and `Feb 10`, and 10 === 10 * const areTheSame = datesAreTheSame(timeFormat)(date1, date2); // true */ const datesBiggerOrEqual = (key) => (currentDate, prevDate) => { const currentTime = getTimeFromDateByTimeFormat(currentDate, key); const prevTime = getTimeFromDateByTimeFormat(prevDate, key); return currentTime >= prevTime; }; //#region TimeFormat matchers const weekdayCheckDict = { 1: isMonday, 2: isTuesday, 3: isWednesday, 4: isThursday, 5: isFriday, 6: isSaturday, 7: isSunday, }; /** * Checks if the given {@link Date} matches with `weekMatchValue` and `weekdayMatchValue` * @example * const date = new Date('Fri Feb 10 2023 14:50:10 GMT+0500'); * // '$' means last week of the month * const weekMatchValue = '$'; * // 5 means Friday * const weekdayMatchValue = 5; * // to sum up '$' and 5 means `last Friday in month` * * // false, because `Feb 10` is 2nd Friday in Feb 2023 * const match = weekWeekdayMatch(date, weekMatchValue, weekdayMatchValue); // false * * @example * const date = new Date('Tue Feb 7 2023 14:50:10 GMT+0500'); * // 1 means first week of the month * const weekMatchValue = 1; * // 2 means Tuesday * const weekdayMatchValue = 2; * // to sum up 1 and 2 means `first Tuesday in month` * * // true, but there's a tricky part: * // Feb 2023 doesn't have a Tuesday on the first week, so for such cases * // match function will take the next week, and search Tuesday on it. * // Therefore weekMatchValue becomes 2, and 2nd weeks' Tuesday in Feb 2023 is Feb 7 * const match = weekWeekdayMatch(date, weekMatchValue, weekdayMatchValue); // true */ const weekWeekdayMatch = (date, weekMatchValue, weekdayMatchValue) => { var _a; const fullMonthInterval = eachDayOfInterval({ start: startOfMonth(date), end: endOfMonth(date), }); const weekdayCheckFn = (_a = weekdayCheckDict[weekdayMatchValue]) !== null && _a !== void 0 ? _a : (() => false); if (weekMatchValue === '$') { for (const dateOfInterval of fullMonthInterval.reverse()) { if (weekdayCheckFn(dateOfInterval)) { return isSameDay(date, dateOfInterval); } } } else { let week = 1; for (const dateOfInterval of fullMonthInterval) { if (weekdayCheckFn(dateOfInterval)) { if (week === weekMatchValue) { return isSameDay(date, dateOfInterval); } else { week++; } } } } return false; }; /** * Checks if the given `value` and `matchValue` match exactly * @example * const match = exactMatch(10, 10); // true * const match = exactMatch(10, 5); // false **/ const exactMatch = (value, matchValue) => { return matchValue === 1 ? value === 1 : value / matchValue === 1; }; /** * Checks if the given `value` is divisible by `matchValue` * const match = looseMatch(10, 5); // true * const match = looseMatch(11, 5); // false */ const looseMatch = (value, matchValue) => { return matchValue === 1 ? true : value % matchValue === 0; }; //#endregion TimeFormat matchers //#region TimeFormat matchers factories const lessThanSecondMatcherFactory = (timeFormat) => (currentDate, prevDate) => datesBiggerOrEqual(timeFormat.key)(currentDate, prevDate); const monthMatcherFactory = (timeFormat) => (currentDate, prevDate) => { const datesNotMatch = datesNOTtheSame(timeFormat.key)(currentDate, prevDate); const valueMatch = timeFormat.exact ? exactMatch(getTimeFromDateByTimeFormat(currentDate, timeFormat.key) + 1, timeFormat.value) : looseMatch(getTimeFromDateByTimeFormat(currentDate, timeFormat.key) + 1, timeFormat.value); return datesNotMatch && valueMatch; }; const commonMatcherFactory = (timeFormat) => (currentDate, prevDate) => { const datesNotMatch = datesNOTtheSame(timeFormat.key)(currentDate, prevDate); const valueMatch = timeFormat.exact ? exactMatch(getTimeFromDateByTimeFormat(currentDate, timeFormat.key), timeFormat.value) : looseMatch(getTimeFromDateByTimeFormat(currentDate, timeFormat.key), timeFormat.value); return datesNotMatch && valueMatch; }; const weekWeekdayMatcherFactory = (timeFormat) => (currentDate, prevDate) => { const datesNotMatch = datesNOTtheSame(timeFormat.key)(currentDate, prevDate); const valueMatch = weekWeekdayMatch(currentDate, timeFormat.week, timeFormat.weekday); return datesNotMatch && valueMatch; }; //#endregion TimeFormat matchers factories