Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(formula): fix formula parameter assignment #2905

Merged
merged 1 commit into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/engine-formula/src/basics/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,13 @@ export function countWorkingDays(startDateSerialNumber: number, endDateSerialNum
export function getDateSerialNumberByWorkingDays(startDateSerialNumber: number, workingDays: number, weekend: number | string = 1, holidays?: number[]): (number | ErrorValueObject) {
const weekendArray = getWeekendArray(weekend);

startDateSerialNumber = Math.floor(startDateSerialNumber);
let targetDateSerialNumber = startDateSerialNumber;
const _startDateSerialNumber = Math.floor(startDateSerialNumber);
let targetDateSerialNumber = _startDateSerialNumber;

let days = Math.abs(workingDays);

for (let i = 1; i <= days; i++) {
const currentDateSerialNumber = workingDays < 0 ? startDateSerialNumber - i : startDateSerialNumber + i;
const currentDateSerialNumber = workingDays < 0 ? _startDateSerialNumber - i : _startDateSerialNumber + i;

if (currentDateSerialNumber < 0) {
return ErrorValueObject.create(ErrorType.NUM);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1370,15 +1370,18 @@ export class StringValueObject extends BaseValueObject {
if (typeof value === 'string') {
// Case sensitivity needs to be considered, most functions are case-insensitive, like VLOOKUP/HLOOKUP/XLOOKUP/MATCH/COUNTIF/COUNTIFS/SUMIF/SUMIFS/SEARCH/FIND(in SUBSTITUTE)
// A few functions are case-sensitive, like EXACT/FIND/FINDB/REPLACE/REPLACEB/MIDB
let _value = value;

if (!isCaseSensitive) {
currentValue = currentValue.toLocaleLowerCase();
value = value.toLocaleLowerCase();
_value = _value.toLocaleLowerCase();
}

if (isWildcard(value)) {
return this._checkWildcard(value, operator);
if (isWildcard(_value)) {
return this._checkWildcard(_value, operator);
}
result = this._compareString(currentValue, value, operator);

result = this._compareString(currentValue, _value, operator);
} else if (typeof value === 'number') {
result = this._compareNumber(operator);
} else if (typeof value === 'boolean') {
Expand Down
18 changes: 10 additions & 8 deletions packages/engine-formula/src/functions/base-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,26 +147,28 @@ export class BaseFunction extends Disposable {
* @param indexNum
*/
getIndexNumValue(indexNum: BaseValueObject, defaultValue = 1) {
if (indexNum.isArray()) {
indexNum = (indexNum as ArrayValueObject).getFirstCell();
let _indexNum = indexNum;

if (_indexNum.isArray()) {
_indexNum = (_indexNum as ArrayValueObject).getFirstCell();
}

if (indexNum.isBoolean()) {
const colIndexNumV = indexNum.getValue() as boolean;
if (_indexNum.isBoolean()) {
const colIndexNumV = _indexNum.getValue() as boolean;
if (colIndexNumV === false) {
return ErrorValueObject.create(ErrorType.VALUE);
}

return defaultValue;
}
if (indexNum.isString()) {
const colIndexNumV = Number(indexNum.getValue() as string);
if (_indexNum.isString()) {
const colIndexNumV = Number(_indexNum.getValue() as string);
if (Number.isNaN(colIndexNumV)) {
return ErrorValueObject.create(ErrorType.REF);
}
return colIndexNumV;
} else if (indexNum.isNumber()) {
const colIndexNumV = indexNum.getValue() as number;
} else if (_indexNum.isNumber()) {
const colIndexNumV = _indexNum.getValue() as number;
return colIndexNumV;
}

Expand Down
64 changes: 32 additions & 32 deletions packages/engine-formula/src/functions/date/datedif/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,41 @@ export class Datedif extends BaseFunction {
override maxParams = 3;

override calculate(startDate: BaseValueObject, endDate: BaseValueObject, unit: BaseValueObject) {
if (startDate.isArray()) {
startDate = (startDate as ArrayValueObject).get(0, 0) as BaseValueObject;
let _startDate = startDate;
let _endDate = endDate;
let _unit = unit;

if (_startDate.isArray()) {
_startDate = (_startDate as ArrayValueObject).get(0, 0) as BaseValueObject;
}

if (endDate.isArray()) {
endDate = (endDate as ArrayValueObject).get(0, 0) as BaseValueObject;
if (_endDate.isArray()) {
_endDate = (_endDate as ArrayValueObject).get(0, 0) as BaseValueObject;
}

if (unit.isArray()) {
unit = (unit as ArrayValueObject).get(0, 0) as BaseValueObject;
if (_unit.isArray()) {
_unit = (_unit as ArrayValueObject).get(0, 0) as BaseValueObject;
}

if (startDate.isError()) {
return startDate;
if (_startDate.isError()) {
return _startDate;
}

if (endDate.isError()) {
return endDate;
if (_endDate.isError()) {
return _endDate;
}

if (unit.isError()) {
return unit;
if (_unit.isError()) {
return _unit;
}

const startDateSerialNumber = getDateSerialNumberByObject(startDate);
const startDateSerialNumber = getDateSerialNumberByObject(_startDate);

if (typeof startDateSerialNumber !== 'number') {
return startDateSerialNumber;
}

let endDateSerialNumber = getDateSerialNumberByObject(endDate);
const endDateSerialNumber = getDateSerialNumberByObject(_endDate);

if (typeof endDateSerialNumber !== 'number') {
return endDateSerialNumber;
Expand All @@ -67,10 +71,14 @@ export class Datedif extends BaseFunction {
return ErrorValueObject.create(ErrorType.NUM);
}

if (!unit.isString()) {
if (!_unit.isString()) {
return ErrorValueObject.create(ErrorType.NUM);
}

return this._getResultByUnit(startDateSerialNumber, endDateSerialNumber, _unit);
}

private _getResultByUnit(startDateSerialNumber: number, endDateSerialNumber: number, unit: BaseValueObject): BaseValueObject {
const startDateDate = excelSerialToDate(startDateSerialNumber);
const startYear = startDateDate.getUTCFullYear();
const startMonth = startDateDate.getUTCMonth() + 1;
Expand All @@ -81,41 +89,33 @@ export class Datedif extends BaseFunction {
const endMonth = endDateDate.getUTCMonth() + 1;
const endDay = endDateDate.getUTCDate();

const unitValue = String(unit.getValue()).toLocaleUpperCase();
const unitValue = `${unit.getValue()}`.toLocaleUpperCase();

let result: number;
let _endDateSerialNumber;

switch (unitValue) {
case 'Y':
// The number of complete years in the period.
result = endYear - startYear;
break;
return NumberValueObject.create(endYear - startYear);
case 'M':
// The number of complete months in the period.
result = (endYear - startYear) * 12 + endMonth - startMonth;
break;
return NumberValueObject.create((endYear - startYear) * 12 + endMonth - startMonth);
case 'D':
// The number of days in the period.
result = Math.floor(endDateSerialNumber) - Math.floor(startDateSerialNumber);
break;
return NumberValueObject.create(Math.floor(endDateSerialNumber) - Math.floor(startDateSerialNumber));
case 'MD':
// The difference between the days in start_date and end_date. The months and years of the dates are ignored.
result = endDay - startDay;
break;
return NumberValueObject.create(endDay - startDay);
case 'YM':
// The difference between the months in start_date and end_date. The days and years of the dates are ignored.
result = endMonth - startMonth;
break;
return NumberValueObject.create(endMonth - startMonth);
case 'YD':
// The difference between the days of start_date and end_date. The years of the dates are ignored.
// The year is the year of the start date
endDateSerialNumber = excelDateSerial(new Date(Date.UTC(startYear, endMonth - 1, endDay)));
result = Math.floor(endDateSerialNumber) - Math.floor(startDateSerialNumber);
break;
_endDateSerialNumber = excelDateSerial(new Date(Date.UTC(startYear, endMonth - 1, endDay)));
return NumberValueObject.create(Math.floor(_endDateSerialNumber) - Math.floor(startDateSerialNumber));
default:
return ErrorValueObject.create(ErrorType.NUM);
}

return NumberValueObject.create(result);
}
}
112 changes: 57 additions & 55 deletions packages/engine-formula/src/functions/date/days360/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export class Days360 extends BaseFunction {
override maxParams = 3;

override calculate(startDate: BaseValueObject, endDate: BaseValueObject, method?: BaseValueObject) {
const _method = method ?? BooleanValueObject.create(false);

if (startDate.isError()) {
return startDate;
}
Expand All @@ -36,29 +38,29 @@ export class Days360 extends BaseFunction {
return endDate;
}

if (method?.isError()) {
return method;
if (_method.isError()) {
return _method;
}

const maxRowLength = Math.max(
startDate.isArray() ? (startDate as ArrayValueObject).getRowCount() : 1,
endDate.isArray() ? (endDate as ArrayValueObject).getRowCount() : 1,
method?.isArray() ? (method as ArrayValueObject).getRowCount() : 1
_method.isArray() ? (_method as ArrayValueObject).getRowCount() : 1
);

const maxColumnLength = Math.max(
startDate.isArray() ? (startDate as ArrayValueObject).getColumnCount() : 1,
endDate.isArray() ? (endDate as ArrayValueObject).getColumnCount() : 1,
method?.isArray() ? (method as ArrayValueObject).getColumnCount() : 1
_method.isArray() ? (_method as ArrayValueObject).getColumnCount() : 1
);

const startDateArray = expandArrayValueObject(maxRowLength, maxColumnLength, startDate, ErrorValueObject.create(ErrorType.NA));
const endDateArray = expandArrayValueObject(maxRowLength, maxColumnLength, endDate, ErrorValueObject.create(ErrorType.NA));
const methodArray = method ? expandArrayValueObject(maxRowLength, maxColumnLength, method, ErrorValueObject.create(ErrorType.NA)) : [];
const methodArray = expandArrayValueObject(maxRowLength, maxColumnLength, _method, ErrorValueObject.create(ErrorType.NA));

const resultArray = startDateArray.map((startDateObject, rowIndex, columnIndex) => {
const endDateObject = endDateArray.get(rowIndex, columnIndex) as BaseValueObject;
let methodObject = method ? (methodArray as ArrayValueObject).get(rowIndex, columnIndex) as BaseValueObject : BooleanValueObject.create(false);
let methodObject = methodArray.get(rowIndex, columnIndex) as BaseValueObject;

if (startDateObject.isError()) {
return startDateObject;
Expand All @@ -80,10 +82,6 @@ export class Days360 extends BaseFunction {
return endDateSerialNumber;
}

if (methodObject.isError()) {
return methodObject;
}

if (methodObject.isString()) {
methodObject = methodObject.convertToNumberObjectValue();
}
Expand All @@ -92,61 +90,65 @@ export class Days360 extends BaseFunction {
return methodObject;
}

const startDateDate = excelSerialToDate(startDateSerialNumber);
const startYear = startDateSerialNumber > 0 ? startDateDate.getUTCFullYear() : 1900;
const startMonth = startDateSerialNumber > 0 ? startDateDate.getUTCMonth() + 1 : 1;
let startDay = startDateSerialNumber > 0 ? startDateDate.getUTCDate() : 0;

let endDateDate = excelSerialToDate(endDateSerialNumber);
let endYear = endDateSerialNumber > 0 ? endDateDate.getUTCFullYear() : 1900;
let endMonth = endDateSerialNumber > 0 ? endDateDate.getUTCMonth() + 1 : 1;
let endDay = endDateSerialNumber > 0 ? endDateDate.getUTCDate() : 0;
return this._getResult(startDateSerialNumber, endDateSerialNumber, methodObject);
});

const methodValue = +methodObject.getValue();
if (maxRowLength === 1 && maxColumnLength === 1) {
return (resultArray as ArrayValueObject).get(0, 0) as NumberValueObject;
}

if (!methodValue) {
// U.S. (NASD) method.
// If the starting date is the last day of a month, it becomes equal to the 30th day of the same month.
// If the ending date is the last day of a month and the starting date is earlier than the 30th day of a month, the ending date becomes equal to the 1st day of the next month; otherwise the ending date becomes equal to the 30th day of the same month.
if (startDay === 31) {
startDay = 30;
}
return resultArray;
}

if (endDay === 31) {
if (startDay < 30) {
endDateDate = excelSerialToDate(endDateSerialNumber + 1);
endYear = endDateDate.getUTCFullYear();
endMonth = endDateDate.getUTCMonth() + 1;
endDay = endDateDate.getUTCDate();
} else {
endDay = 30;
}
}
} else {
// European method. Starting dates and ending dates that occur on the 31st day of a month become equal to the 30th day of the same month.
if (startDay === 31) {
startDay = 30;
}
private _getResult(startDateSerialNumber: number, endDateSerialNumber: number, methodObject: BaseValueObject) {
const startDateDate = excelSerialToDate(startDateSerialNumber);
const startYear = startDateSerialNumber > 0 ? startDateDate.getUTCFullYear() : 1900;
const startMonth = startDateSerialNumber > 0 ? startDateDate.getUTCMonth() + 1 : 1;
let startDay = startDateSerialNumber > 0 ? startDateDate.getUTCDate() : 0;

let endDateDate = excelSerialToDate(endDateSerialNumber);
let endYear = endDateSerialNumber > 0 ? endDateDate.getUTCFullYear() : 1900;
let endMonth = endDateSerialNumber > 0 ? endDateDate.getUTCMonth() + 1 : 1;
let endDay = endDateSerialNumber > 0 ? endDateDate.getUTCDate() : 0;

const methodValue = +methodObject.getValue();

if (!methodValue) {
// U.S. (NASD) method.
// If the starting date is the last day of a month, it becomes equal to the 30th day of the same month.
// If the ending date is the last day of a month and the starting date is earlier than the 30th day of a month, the ending date becomes equal to the 1st day of the next month; otherwise the ending date becomes equal to the 30th day of the same month.
if (startDay === 31) {
startDay = 30;
}

if (endDay === 31) {
if (endDay === 31) {
if (startDay < 30) {
endDateDate = excelSerialToDate(endDateSerialNumber + 1);
endYear = endDateDate.getUTCFullYear();
endMonth = endDateDate.getUTCMonth() + 1;
endDay = endDateDate.getUTCDate();
} else {
endDay = 30;
}
}
} else {
// European method. Starting dates and ending dates that occur on the 31st day of a month become equal to the 30th day of the same month.
if (startDay === 31) {
startDay = 30;
}

const daysInYears = (endYear - startYear) * 360;
const daysInStartMonth = endDateSerialNumber >= startDateSerialNumber ? 30 - startDay : -startDay;
const daysInEndMonth = endDateSerialNumber >= startDateSerialNumber ? endDay : endDay - 30;
const daysInMidMonths = (endDateSerialNumber >= startDateSerialNumber ? (endMonth - startMonth - 1) : (endMonth - startMonth + 1)) * 30;

const totalDays = daysInYears + daysInStartMonth + daysInEndMonth + daysInMidMonths;
if (endDay === 31) {
endDay = 30;
}
}

return NumberValueObject.create(totalDays);
});
const daysInYears = (endYear - startYear) * 360;
const daysInStartMonth = endDateSerialNumber >= startDateSerialNumber ? 30 - startDay : -startDay;
const daysInEndMonth = endDateSerialNumber >= startDateSerialNumber ? endDay : endDay - 30;
const daysInMidMonths = (endDateSerialNumber >= startDateSerialNumber ? (endMonth - startMonth - 1) : (endMonth - startMonth + 1)) * 30;

if (maxRowLength === 1 && maxColumnLength === 1) {
return (resultArray as ArrayValueObject).get(0, 0) as NumberValueObject;
}
const totalDays = daysInYears + daysInStartMonth + daysInEndMonth + daysInMidMonths;

return resultArray;
return NumberValueObject.create(totalDays);
}
}
12 changes: 5 additions & 7 deletions packages/engine-formula/src/functions/date/edate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,16 @@ export class Edate extends BaseFunction {

const monthsValue = Math.floor(+monthsValueObject.getValue());

const startDate = excelSerialToDate(startDateSerial);
const _startDate = excelSerialToDate(startDateSerial);

const year = startDate.getUTCFullYear();
const month = startDate.getUTCMonth() + monthsValue;
const day = startDate.getUTCDate();
const year = _startDate.getUTCFullYear();
const month = _startDate.getUTCMonth() + monthsValue;
const day = _startDate.getUTCDate();

const resultDate = new Date(Date.UTC(year, month, day));
const currentSerial = excelDateSerial(resultDate);

const valueObject = NumberValueObject.create(currentSerial, DEFAULT_DATE_FORMAT);

return valueObject;
return NumberValueObject.create(currentSerial, DEFAULT_DATE_FORMAT);
});
}
}
Loading
Loading