devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
720 lines (694 loc) • 25.4 kB
JavaScript
/**
* DevExtreme (cjs/__internal/core/utils/m_date.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.dateUtils = void 0;
var _date_serialization = _interopRequireDefault(require("../../../core/utils/date_serialization"));
var _inflector = require("../../../core/utils/inflector");
var _iterator = require("../../../core/utils/iterator");
var _math = require("../../../core/utils/math");
var _type = require("../../../core/utils/type");
var _toMilliseconds = require("../../utils/toMilliseconds");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const DAYS_IN_WEEK = 7;
const THURSDAY_WEEK_NUMBER = 4;
const SUNDAY_WEEK_NUMBER = 7;
const USUAL_WEEK_COUNT_IN_YEAR = 52;
const dateUnitIntervals = ["millisecond", "second", "minute", "hour", "day", "week", "month", "quarter", "year"];
const getDatesInterval = function(startDate, endDate, intervalUnit) {
const delta = endDate.getTime() - startDate.getTime();
const millisecondCount = (0, _toMilliseconds.toMilliseconds)(intervalUnit) || 1;
return Math.floor(delta / millisecondCount)
};
const getNextDateUnit = function(unit, withWeeks) {
const interval = getDateUnitInterval(unit);
switch (interval) {
case "millisecond":
return "second";
case "second":
return "minute";
case "minute":
return "hour";
case "hour":
return "day";
case "day":
return withWeeks ? "week" : "month";
case "week":
return "month";
case "month":
return "quarter";
case "quarter":
case "year":
return "year";
default:
return 0
}
};
const convertMillisecondsToDateUnits = function(value) {
let i;
let dateUnitCount;
let dateUnitInterval;
const dateUnitIntervals = ["millisecond", "second", "minute", "hour", "day", "month", "year"];
const result = {};
for (i = dateUnitIntervals.length - 1; i >= 0; i--) {
dateUnitInterval = dateUnitIntervals[i];
dateUnitCount = Math.floor(value / (0, _toMilliseconds.toMilliseconds)(dateUnitInterval));
if (dateUnitCount > 0) {
result[`${dateUnitInterval}s`] = dateUnitCount;
value -= convertDateUnitToMilliseconds(dateUnitInterval, dateUnitCount)
}
}
return result
};
const dateToMilliseconds = function(tickInterval) {
let milliseconds = 0;
if ((0, _type.isObject)(tickInterval)) {
(0, _iterator.each)(tickInterval, (function(key, value) {
milliseconds += convertDateUnitToMilliseconds(key.substr(0, key.length - 1), value)
}))
}
if ((0, _type.isString)(tickInterval)) {
milliseconds = convertDateUnitToMilliseconds(tickInterval, 1)
}
return milliseconds
};
function convertDateUnitToMilliseconds(dateUnit, count) {
return (0, _toMilliseconds.toMilliseconds)(dateUnit) * count
}
function getDateUnitInterval(tickInterval) {
let maxInterval = -1;
let i;
if ((0, _type.isString)(tickInterval)) {
return tickInterval
}
if ((0, _type.isObject)(tickInterval)) {
(0, _iterator.each)(tickInterval, (function(key, value) {
for (i = 0; i < dateUnitIntervals.length; i++) {
if (value && (key === `${dateUnitIntervals[i]}s` || key === dateUnitIntervals[i]) && maxInterval < i) {
maxInterval = i
}
}
}));
return dateUnitIntervals[maxInterval]
}
return ""
}
const tickIntervalToFormatMap = {
millisecond: "millisecond",
second: "longtime",
minute: "shorttime",
hour: "shorttime",
day: "day",
week: "day",
month: "month",
quarter: "quarter",
year: "year"
};
function getDateFormatByTickInterval(tickInterval) {
return tickIntervalToFormatMap[getDateUnitInterval(tickInterval)] || ""
}
const getQuarter = function(month) {
return Math.floor(month / 3)
};
const getFirstQuarterMonth = function(month) {
return 3 * getQuarter(month)
};
function correctDateWithUnitBeginning(date, dateInterval, withCorrection, firstDayOfWeek) {
date = new Date(date.getTime());
const oldDate = new Date(date.getTime());
let firstQuarterMonth;
let month;
const dateUnitInterval = getDateUnitInterval(dateInterval);
switch (dateUnitInterval) {
case "second":
date = new Date(1e3 * Math.floor(oldDate.getTime() / 1e3));
break;
case "minute":
date = new Date(6e4 * Math.floor(oldDate.getTime() / 6e4));
break;
case "hour":
date = new Date(36e5 * Math.floor(oldDate.getTime() / 36e5));
break;
case "year":
date.setMonth(0);
case "month":
date.setDate(1);
case "day":
date.setHours(0, 0, 0, 0);
break;
case "week":
date = getFirstWeekDate(date, firstDayOfWeek || 0);
date.setHours(0, 0, 0, 0);
break;
case "quarter":
firstQuarterMonth = getFirstQuarterMonth(date.getMonth());
month = date.getMonth();
date.setDate(1);
date.setHours(0, 0, 0, 0);
if (month !== firstQuarterMonth) {
date.setMonth(firstQuarterMonth)
}
}
if (withCorrection && "hour" !== dateUnitInterval && "minute" !== dateUnitInterval && "second" !== dateUnitInterval) {
fixTimezoneGap(oldDate, date)
}
return date
}
function trimTime(date) {
return correctDateWithUnitBeginning(date, "day")
}
const setToDayEnd = function(date) {
const result = trimTime(date);
result.setDate(result.getDate() + 1);
return new Date(result.getTime() - 1)
};
const getDatesDifferences = function(date1, date2) {
let counter = 0;
const differences = {
year: date1.getFullYear() !== date2.getFullYear(),
month: date1.getMonth() !== date2.getMonth(),
day: date1.getDate() !== date2.getDate(),
hour: date1.getHours() !== date2.getHours(),
minute: date1.getMinutes() !== date2.getMinutes(),
second: date1.getSeconds() !== date2.getSeconds(),
millisecond: date1.getMilliseconds() !== date2.getMilliseconds()
};
(0, _iterator.each)(differences, (function(key, value) {
if (value) {
counter++
}
}));
if (0 === counter && 0 !== getTimezonesDifference(date1, date2)) {
differences.hour = true;
counter++
}
differences.count = counter;
return differences
};
function addDateInterval(value, interval, dir) {
const result = new Date(value.getTime());
const intervalObject = (0, _type.isString)(interval) ? getDateIntervalByString(interval.toLowerCase()) : (0, _type.isNumeric)(interval) ? convertMillisecondsToDateUnits(interval) : interval;
if (intervalObject.years) {
result.setFullYear(result.getFullYear() + intervalObject.years * dir)
}
if (intervalObject.quarters) {
result.setMonth(result.getMonth() + 3 * intervalObject.quarters * dir)
}
if (intervalObject.months) {
result.setMonth(result.getMonth() + intervalObject.months * dir)
}
if (intervalObject.weeks) {
result.setDate(result.getDate() + 7 * intervalObject.weeks * dir)
}
if (intervalObject.days) {
result.setDate(result.getDate() + intervalObject.days * dir)
}
if (intervalObject.hours) {
result.setTime(result.getTime() + 36e5 * intervalObject.hours * dir)
}
if (intervalObject.minutes) {
result.setTime(result.getTime() + 6e4 * intervalObject.minutes * dir)
}
if (intervalObject.seconds) {
result.setTime(result.getTime() + 1e3 * intervalObject.seconds * dir)
}
if (intervalObject.milliseconds) {
result.setTime(result.getTime() + intervalObject.milliseconds * dir)
}
return result
}
const addInterval = function(value, interval, isNegative) {
const dir = isNegative ? -1 : 1;
return (0, _type.isDate)(value) ? addDateInterval(value, interval, dir) : (0, _math.adjust)(value + interval * dir, interval)
};
const getSequenceByInterval = function(min, max, interval) {
const intervals = [];
let cur;
intervals.push((0, _type.isDate)(min) ? new Date(min.getTime()) : min);
cur = min;
while (cur < max) {
cur = addInterval(cur, interval);
intervals.push(cur)
}
return intervals
};
const getViewFirstCellDate = function(viewType, date) {
if ("month" === viewType) {
return createDateWithFullYear(date.getFullYear(), date.getMonth(), 1)
}
if ("year" === viewType) {
return createDateWithFullYear(date.getFullYear(), 0, date.getDate())
}
if ("decade" === viewType) {
return createDateWithFullYear(getFirstYearInDecade(date), date.getMonth(), date.getDate())
}
if ("century" === viewType) {
return createDateWithFullYear(getFirstDecadeInCentury(date), date.getMonth(), date.getDate())
}
};
const getViewLastCellDate = function(viewType, date) {
if ("month" === viewType) {
return createDateWithFullYear(date.getFullYear(), date.getMonth(), getLastMonthDay(date))
}
if ("year" === viewType) {
return createDateWithFullYear(date.getFullYear(), 11, date.getDate())
}
if ("decade" === viewType) {
return createDateWithFullYear(getFirstYearInDecade(date) + 9, date.getMonth(), date.getDate())
}
if ("century" === viewType) {
return createDateWithFullYear(getFirstDecadeInCentury(date) + 90, date.getMonth(), date.getDate())
}
};
const getViewMinBoundaryDate = function(viewType, date) {
const resultDate = createDateWithFullYear(date.getFullYear(), date.getMonth(), 1);
if ("month" === viewType) {
return resultDate
}
resultDate.setMonth(0);
if ("year" === viewType) {
return resultDate
}
if ("decade" === viewType) {
resultDate.setFullYear(getFirstYearInDecade(date))
}
if ("century" === viewType) {
resultDate.setFullYear(getFirstDecadeInCentury(date))
}
return resultDate
};
const getViewMaxBoundaryDate = function(viewType, date) {
const resultDate = new Date(date);
resultDate.setDate(getLastMonthDay(date));
if ("month" === viewType) {
return resultDate
}
resultDate.setMonth(11);
resultDate.setDate(getLastMonthDay(resultDate));
if ("year" === viewType) {
return resultDate
}
if ("decade" === viewType) {
resultDate.setFullYear(getFirstYearInDecade(date) + 9)
}
if ("century" === viewType) {
resultDate.setFullYear(getFirstDecadeInCentury(date) + 99)
}
return resultDate
};
function getLastMonthDay(date) {
const resultDate = createDateWithFullYear(date.getFullYear(), date.getMonth() + 1, 0);
return resultDate.getDate()
}
const getViewUp = function(typeView) {
switch (typeView) {
case "month":
return "year";
case "year":
return "decade";
case "decade":
return "century"
}
};
const getViewDown = function(typeView) {
switch (typeView) {
case "century":
return "decade";
case "decade":
return "year";
case "year":
return "month"
}
};
const getDifferenceInMonth = function(typeView) {
let difference = 1;
if ("year" === typeView) {
difference = 12
}
if ("decade" === typeView) {
difference = 120
}
if ("century" === typeView) {
difference = 1200
}
return difference
};
const getDifferenceInMonthForCells = function(typeView) {
let difference = 1;
if ("decade" === typeView) {
difference = 12
}
if ("century" === typeView) {
difference = 120
}
return difference
};
function getDateIntervalByString(intervalString) {
const result = {};
switch (intervalString) {
case "year":
result.years = 1;
break;
case "month":
result.months = 1;
break;
case "quarter":
result.months = 3;
break;
case "week":
result.weeks = 1;
break;
case "day":
result.days = 1;
break;
case "hour":
result.hours = 1;
break;
case "minute":
result.minutes = 1;
break;
case "second":
result.seconds = 1;
break;
case "millisecond":
result.milliseconds = 1
}
return result
}
function sameDate(date1, date2) {
return sameMonthAndYear(date1, date2) && date1.getDate() === date2.getDate()
}
function sameMonthAndYear(date1, date2) {
return sameYear(date1, date2) && date1.getMonth() === date2.getMonth()
}
function sameYear(date1, date2) {
return date1 && date2 && date1.getFullYear() === date2.getFullYear()
}
function sameHoursAndMinutes(date1, date2) {
return date1 && date2 && date1.getHours() === date2.getHours() && date1.getMinutes() === date2.getMinutes()
}
const sameDecade = function(date1, date2) {
if (!(0, _type.isDefined)(date1) || !(0, _type.isDefined)(date2)) {
return
}
const startDecadeDate1 = date1.getFullYear() - date1.getFullYear() % 10;
const startDecadeDate2 = date2.getFullYear() - date2.getFullYear() % 10;
return date1 && date2 && startDecadeDate1 === startDecadeDate2
};
const sameCentury = function(date1, date2) {
if (!(0, _type.isDefined)(date1) || !(0, _type.isDefined)(date2)) {
return
}
const startCenturyDate1 = date1.getFullYear() - date1.getFullYear() % 100;
const startCenturyDate2 = date2.getFullYear() - date2.getFullYear() % 100;
return date1 && date2 && startCenturyDate1 === startCenturyDate2
};
function getFirstDecadeInCentury(date) {
return date && date.getFullYear() - date.getFullYear() % 100
}
function getFirstYearInDecade(date) {
return date && date.getFullYear() - date.getFullYear() % 10
}
const getShortDateFormat = function() {
return "yyyy/MM/dd"
};
const getFirstMonthDate = function(date) {
let offset = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
if (!(0, _type.isDefined)(date)) {
return
}
const currentDate = new Date(date.getTime());
const month = currentDate.getMonth() + offset;
currentDate.setMonth(month);
return createDateWithFullYear(currentDate.getFullYear(), month, 1)
};
const getLastMonthDate = function(date) {
let offset = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
if (!(0, _type.isDefined)(date)) {
return
}
const currentDate = new Date(date.getTime());
const month = currentDate.getMonth() + offset;
currentDate.setMonth(month);
return createDateWithFullYear(currentDate.getFullYear(), month + 1, 0)
};
function getFirstWeekDate(date, firstDayOfWeek) {
const delta = (date.getDay() - firstDayOfWeek + 7) % 7;
const result = new Date(date);
result.setDate(date.getDate() - delta);
return result
}
function getUTCTime(date) {
return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())
}
function getDayNumber(date) {
const ms = getUTCTime(date) - getUTCTime(getFirstDateInYear(date.getFullYear()));
return 1 + Math.floor(ms / (0, _toMilliseconds.toMilliseconds)("day"))
}
function getFirstDateInYear(year) {
return new Date(year, 0, 1)
}
function getLastDateInYear(year) {
return new Date(year, 11, 31)
}
function getDayWeekNumber(date, firstDayOfWeek) {
let day = date.getDay() - firstDayOfWeek + 1;
if (day <= 0) {
day += 7
}
return day
}
function getWeekNumber(date, firstDayOfWeek, rule) {
const firstWeekDayInYear = getDayWeekNumber(getFirstDateInYear(date.getFullYear()), firstDayOfWeek);
const lastWeekDayInYear = getDayWeekNumber(getLastDateInYear(date.getFullYear()), firstDayOfWeek);
const daysInFirstWeek = 7 - firstWeekDayInYear + 1;
let weekNumber = Math.ceil((getDayNumber(date) - daysInFirstWeek) / 7);
switch (rule) {
case "fullWeek":
if (7 === daysInFirstWeek) {
weekNumber++
}
if (0 === weekNumber) {
const lastDateInPreviousYear = getLastDateInYear(date.getFullYear() - 1);
return getWeekNumber(lastDateInPreviousYear, firstDayOfWeek, rule)
}
return weekNumber;
case "firstDay": {
if (daysInFirstWeek > 0) {
weekNumber++
}
const isSunday = 7 === firstWeekDayInYear || 7 === lastWeekDayInYear;
if (weekNumber > 52 && !isSunday || 54 === weekNumber) {
weekNumber = 1
}
return weekNumber
}
case "firstFourDays": {
if (daysInFirstWeek > 3) {
weekNumber++
}
const isThursday = 4 === firstWeekDayInYear || 4 === lastWeekDayInYear;
if (weekNumber > 52 && !isThursday) {
weekNumber = 1
}
if (0 === weekNumber) {
const lastDateInPreviousYear = getLastDateInYear(date.getFullYear() - 1);
return getWeekNumber(lastDateInPreviousYear, firstDayOfWeek, rule)
}
return weekNumber
}
}
}
const normalizeDateByWeek = function(date, currentDate) {
const differenceInDays = dateUtils.getDatesInterval(date, currentDate, "day");
let resultDate = new Date(date);
if (differenceInDays >= 6) {
resultDate = new Date(resultDate.setDate(resultDate.getDate() + 7))
}
return resultDate
};
const dateInRange = function(date, min, max, format) {
if ("date" === format) {
min = min && dateUtils.correctDateWithUnitBeginning(min, "day");
max = max && dateUtils.correctDateWithUnitBeginning(max, "day");
date = date && dateUtils.correctDateWithUnitBeginning(date, "day")
}
return normalizeDate(date, min, max) === date
};
const intervalsOverlap = function(options) {
const {
firstMin: firstMin,
firstMax: firstMax,
secondMin: secondMin,
secondMax: secondMax
} = options;
return firstMin <= secondMin && secondMin <= firstMax || firstMin > secondMin && firstMin < secondMax || firstMin < secondMax && firstMax > secondMax
};
const dateTimeFromDecimal = function(number) {
const hours = Math.floor(number);
const minutes = number % 1 * 60;
return {
hours: hours,
minutes: minutes
}
};
const roundDateByStartDayHour = function(date, startDayHour) {
const startTime = this.dateTimeFromDecimal(startDayHour);
const result = new Date(date);
if (date.getHours() === startTime.hours && date.getMinutes() < startTime.minutes || date.getHours() < startTime.hours) {
result.setHours(startTime.hours, startTime.minutes, 0, 0)
}
return result
};
function normalizeDate(date, min, max) {
let normalizedDate = date;
if (!(0, _type.isDefined)(date)) {
return date
}
if ((0, _type.isDefined)(min) && date < min) {
normalizedDate = min
}
if ((0, _type.isDefined)(max) && date > max) {
normalizedDate = max
}
return normalizedDate
}
function fixTimezoneGap(oldDate, newDate) {
if (!(0, _type.isDefined)(oldDate)) {
return
}
const diff = newDate.getHours() - oldDate.getHours();
if (0 === diff) {
return
}
const sign = 1 === diff || -23 === diff ? -1 : 1;
const trial = new Date(newDate.getTime() + 36e5 * sign);
if (sign > 0 || trial.getDate() === newDate.getDate()) {
newDate.setTime(trial.getTime())
}
}
const roundToHour = function(date) {
const result = new Date(date.getTime());
result.setHours(result.getHours() + 1);
result.setMinutes(0);
return result
};
function getTimezonesDifference(min, max) {
return 60 * (max.getTimezoneOffset() - min.getTimezoneOffset()) * 1e3
}
const makeDate = function(date) {
return new Date(date)
};
const getDatesOfInterval = function(startDate, endDate, step) {
const result = [];
let currentDate = new Date(startDate.getTime());
while (currentDate < endDate) {
result.push(new Date(currentDate.getTime()));
currentDate = this.addInterval(currentDate, step)
}
return result
};
const createDateWithFullYear = function(year) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key]
}
const result = new Date(year, ...args);
result.setFullYear(year);
return result
};
const getMachineTimezoneName = () => {
const hasIntl = "undefined" !== typeof Intl;
return hasIntl ? Intl.DateTimeFormat().resolvedOptions().timeZone : null
};
const getRangesByDates = dates => {
const datesInMilliseconds = dates.map((value => correctDateWithUnitBeginning(value, "day").getTime()));
const sortedDates = datesInMilliseconds.sort(((a, b) => a - b));
const msInDay = (0, _toMilliseconds.toMilliseconds)("day");
const ranges = [];
let startDate = sortedDates[0];
for (let i = 1; i <= sortedDates.length; ++i) {
const nextDate = sortedDates[i];
const currentDate = sortedDates[i - 1];
const isNewRange = nextDate - currentDate > msInDay;
if (isNewRange || i === sortedDates.length) {
const range = startDate === sortedDates[i - 1] ? [startDate] : [startDate, sortedDates[i - 1]];
const serializedRange = range.map((value => _date_serialization.default.deserializeDate(value)));
ranges.push(serializedRange);
startDate = nextDate
}
}
return ranges
};
const sameView = function(view, date1, date2) {
return dateUtils[(0, _inflector.camelize)(`same ${view}`)](date1, date2)
};
const dateUtils = exports.dateUtils = {
dateUnitIntervals: dateUnitIntervals,
convertMillisecondsToDateUnits: convertMillisecondsToDateUnits,
dateToMilliseconds: dateToMilliseconds,
getNextDateUnit: getNextDateUnit,
convertDateUnitToMilliseconds: convertDateUnitToMilliseconds,
getDateUnitInterval: getDateUnitInterval,
getDateFormatByTickInterval: getDateFormatByTickInterval,
getDatesDifferences: getDatesDifferences,
correctDateWithUnitBeginning: correctDateWithUnitBeginning,
trimTime: trimTime,
setToDayEnd: setToDayEnd,
roundDateByStartDayHour: roundDateByStartDayHour,
dateTimeFromDecimal: dateTimeFromDecimal,
addDateInterval: addDateInterval,
addInterval: addInterval,
getSequenceByInterval: getSequenceByInterval,
getDateIntervalByString: getDateIntervalByString,
sameHoursAndMinutes: sameHoursAndMinutes,
sameDate: sameDate,
sameMonthAndYear: sameMonthAndYear,
sameMonth: sameMonthAndYear,
sameYear: sameYear,
sameDecade: sameDecade,
sameCentury: sameCentury,
sameView: sameView,
getDifferenceInMonth: getDifferenceInMonth,
getDifferenceInMonthForCells: getDifferenceInMonthForCells,
getFirstYearInDecade: getFirstYearInDecade,
getFirstDecadeInCentury: getFirstDecadeInCentury,
getShortDateFormat: getShortDateFormat,
getViewFirstCellDate: getViewFirstCellDate,
getViewLastCellDate: getViewLastCellDate,
getViewDown: getViewDown,
getViewUp: getViewUp,
getLastMonthDay: getLastMonthDay,
getLastMonthDate: getLastMonthDate,
getFirstMonthDate: getFirstMonthDate,
getFirstWeekDate: getFirstWeekDate,
getWeekNumber: getWeekNumber,
normalizeDateByWeek: normalizeDateByWeek,
getQuarter: getQuarter,
getFirstQuarterMonth: getFirstQuarterMonth,
dateInRange: dateInRange,
intervalsOverlap: intervalsOverlap,
roundToHour: roundToHour,
normalizeDate: normalizeDate,
getViewMinBoundaryDate: getViewMinBoundaryDate,
getViewMaxBoundaryDate: getViewMaxBoundaryDate,
fixTimezoneGap: fixTimezoneGap,
getTimezonesDifference: getTimezonesDifference,
makeDate: makeDate,
getDatesInterval: getDatesInterval,
getDatesOfInterval: getDatesOfInterval,
createDateWithFullYear: createDateWithFullYear,
getMachineTimezoneName: getMachineTimezoneName,
getRangesByDates: getRangesByDates
};