From 2c53771589d5241c66ba2968a34c7f907119f16b Mon Sep 17 00:00:00 2001 From: DimitryOrlov Date: Wed, 18 Oct 2023 17:47:03 +0400 Subject: [PATCH] [se]Fix bug 49355 (#3908) * [se]Fix bug 49355 --- .../FormulaObjects/dateandtimeFunctions.js | 67 +++---- common/NumFormat.js | 3 + .../spreadsheet-calculation/FormulaTests.js | 166 ++++++++++++++++++ 3 files changed, 203 insertions(+), 33 deletions(-) diff --git a/cell/model/FormulaObjects/dateandtimeFunctions.js b/cell/model/FormulaObjects/dateandtimeFunctions.js index c8ac8282cf..d07f4c5bd2 100644 --- a/cell/model/FormulaObjects/dateandtimeFunctions.js +++ b/cell/model/FormulaObjects/dateandtimeFunctions.js @@ -898,33 +898,29 @@ cDAYS.prototype.isXLFN = true; cDAYS.prototype.argumentsType = [argType.number, argType.number]; cDAYS.prototype.Calculate = function (arg) { - var oArguments = this._prepareArguments(arg, arguments[1], true); - var argClone = oArguments.args; + let oArguments = this._prepareArguments(arg, arguments[1], true); + let argClone = oArguments.args; - var calulateDay = function(curArg) { - var val; - if (curArg instanceof cArray) { + const calulateDay = function(curArg) { + let val; + if (curArg.type === cElementType.cell || curArg.type === cElementType.cell3D) { + curArg = curArg.getValue(); + } else if (curArg.type === cElementType.array) { curArg = curArg.getElement(0); - } else if (curArg instanceof cArea || curArg instanceof cArea3D) { - curArg = curArg.cross(arguments[1]).tocNumber(); - val = curArg.tocNumber().getValue(); + } else if (curArg.type === cElementType.cellsRange || curArg.type === cElementType.cellsRange3D) { + curArg = curArg.cross(arguments[1]); } - if (curArg instanceof cError) { - return curArg; - } else if (curArg instanceof cNumber || curArg instanceof cBool || curArg instanceof cEmpty) { - val = curArg.tocNumber().getValue(); - } else if (curArg instanceof cRef || curArg instanceof cRef3D) { - val = curArg.getValue().tocNumber(); - if (val instanceof cNumber || val instanceof cBool || curArg instanceof cEmpty) { - val = curArg.tocNumber().getValue(); - } else { - return new cError(cErrorType.wrong_value_type); - } - } else if (curArg instanceof cString) { - val = curArg.tocNumber(); - if (val instanceof cError || val instanceof cEmpty) { - var d = new cDate(curArg.getValue()); + val = curArg ? curArg : new cNumber(0); + + if (val.type === cElementType.error) { + return val; + } else if (val.type === cElementType.number || val.type === cElementType.bool || val.type === cElementType.empty) { + val = val.tocNumber().getValue(); + } else if (val.type === cElementType.string) { + val = val.tocNumber(); + if (val.type === cElementType.error || val.type === cElementType.empty) { + let d = new cDate(val.getValue()); if (isNaN(d)) { return new cError(cErrorType.wrong_value_type); } else { @@ -932,24 +928,29 @@ ( AscCommonExcel.c_DateCorrectConst + (AscCommon.bDate1904 ? 0 : 1) )); } } else { - val = curArg.tocNumber().getValue(); + val = val.tocNumber().getValue(); } } return val; }; - var calulateDays = function (argArray) { - var val = calulateDay(argArray[0]); - var val1 = calulateDay(argArray[1]); - if(val instanceof cError) { - return val; - } else if(val1 instanceof cError) { - return val1; - } else if (val < 0 || val1 < 0) { + const calulateDays = function (argArray) { + let end_date = calulateDay(argArray[0]); + let start_date = calulateDay(argArray[1]); + if (end_date.type === cElementType.error) { + return end_date; + } else if (start_date.type === cElementType.error) { + return start_date; + } + + if (end_date < 0 || start_date < 0) { return new cError(cErrorType.not_numeric); } else { - return new cNumber(val - val1); + let endInteger = Math.floor(end_date); + let startInteger = Math.floor(start_date); + return new cNumber(endInteger - startInteger); + } }; diff --git a/common/NumFormat.js b/common/NumFormat.js index 70d11f7cd4..0cdd409c29 100644 --- a/common/NumFormat.js +++ b/common/NumFormat.js @@ -1656,6 +1656,8 @@ NumFormat.prototype = year = 1900; dayWeek = 3; } + // todo test converting all positive fractional values less than one into dates + // else if(numberAbs === 0 || (numberAbs > 0 && numberAbs < 1)) else if(numberAbs === 0) { //TODO необходимо использовать cDate везде @@ -1669,6 +1671,7 @@ NumFormat.prototype = { stDate = new Date(Date.UTC(1899,11,31,0,0,0)); if(d.val) + // setUTCDate doesn't consider the transition from 1899 to 1900 when adding d.val stDate.setUTCDate( stDate.getUTCDate() + d.val ); day = stDate.getUTCDate(); dayWeek = ( stDate.getUTCDay() > 0) ? stDate.getUTCDay() - 1 : 6; diff --git a/tests/cell/spreadsheet-calculation/FormulaTests.js b/tests/cell/spreadsheet-calculation/FormulaTests.js index 0c0a6e1dbf..604763e598 100644 --- a/tests/cell/spreadsheet-calculation/FormulaTests.js +++ b/tests/cell/spreadsheet-calculation/FormulaTests.js @@ -4181,6 +4181,7 @@ $(function () { }); QUnit.test("Test: DAYS", function (assert) { + let array; ws.getRange2("A2").setValue("12/31/2011"); ws.getRange2("A3").setValue("1/1/2011"); @@ -4204,6 +4205,171 @@ $(function () { assert.ok(oParser.parse()); assert.strictEqual(oParser.calculate().getValue(), -2); + ws.getRange2("B3").setValue("44229.4673611111"); + ws.getRange2("B4").setValue("44229.46875"); + ws.getRange2("B5").setValue("1"); + ws.getRange2("B6").setValue("1.9"); + ws.getRange2("B7").setValue("2.1"); + ws.getRange2("B8").setValue("10"); + + oParser = new parserFormula('DAYS(B4,B3)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B4,B3)'); + assert.strictEqual(oParser.calculate().getValue(), 0, 'Result of DAYS(B4,B3)'); + + oParser = new parserFormula('DAYS(B5,B8)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B5,B8)'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS(B5,B8)'); + + oParser = new parserFormula('DAYS(1,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(1,10)'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS(1,10)'); + + oParser = new parserFormula('DAYS(B6,B8)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B6,B8)'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS(B6,B8)'); + + oParser = new parserFormula('DAYS(1.9,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(1.9,10)'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS(1.9,10)'); + + oParser = new parserFormula('DAYS(B7,B8)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B7,B8)'); + assert.strictEqual(oParser.calculate().getValue(), -8, 'Result of DAYS(B7,B8)'); + + oParser = new parserFormula('DAYS(2.1,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(2.1,10)'); + assert.strictEqual(oParser.calculate().getValue(), -8, 'Result of DAYS(2.1,10)'); + + oParser = new parserFormula('DAYS(2.1,10.1)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(2.1,10.1)'); + assert.strictEqual(oParser.calculate().getValue(), -8, 'Result of DAYS(2.1,10.1)'); + + oParser = new parserFormula('DAYS(2.1,10.9)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(2.1,10.9)'); + assert.strictEqual(oParser.calculate().getValue(), -8, 'Result of DAYS(2.1,10.9)'); + + oParser = new parserFormula('DAYS(2.1,-10.9)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(2.1,-10.9)'); + assert.strictEqual(oParser.calculate().getValue(), "#NUM!", 'Result of DAYS(2.1,-10.9)'); + + oParser = new parserFormula('DAYS(-2.1,10.9)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(-2.1,10.9)'); + assert.strictEqual(oParser.calculate().getValue(), "#NUM!", 'Result of DAYS(2.1,10.9)'); + + oParser = new parserFormula('DAYS(-2.1,-10.9)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(-2.1,-10.9)'); + assert.strictEqual(oParser.calculate().getValue(), "#NUM!", 'Result of DAYS(-2.1,-10.9)'); + + oParser = new parserFormula('DAYS(,10.9)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(,10.9)'); + assert.strictEqual(oParser.calculate().getValue(), -10, 'Result of DAYS(,10.9)'); + + oParser = new parserFormula('DAYS(2.1,)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(2.1,)'); + assert.strictEqual(oParser.calculate().getValue(), 2, 'Result of DAYS(2.1,)'); + + oParser = new parserFormula('DAYS(,)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(,)'); + assert.strictEqual(oParser.calculate().getValue(), 0, 'Result of DAYS(,)'); + + // string + oParser = new parserFormula('DAYS("1","10")', "A1", ws); + assert.ok(oParser.parse(), 'DAYS("1","10")'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS("1","10")'); + + oParser = new parserFormula('DAYS("1s","10")', "A1", ws); + assert.ok(oParser.parse(), 'DAYS("1s","10")'); + assert.strictEqual(oParser.calculate().getValue(), "#VALUE!", 'Result of DAYS("1s","10")'); + + oParser = new parserFormula('DAYS("1","10s")', "A1", ws); + assert.ok(oParser.parse(), 'DAYS("1","10s")'); + assert.strictEqual(oParser.calculate().getValue(), "#VALUE!", 'Result of DAYS("1","10s")'); + + // bool + oParser = new parserFormula('DAYS(TRUE,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(TRUE,10)'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS(TRUE,10)'); + + oParser = new parserFormula('DAYS(FALSE,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(FALSE,10)'); + assert.strictEqual(oParser.calculate().getValue(), -10, 'Result of DAYS(FALSE,10)'); + + oParser = new parserFormula('DAYS(1,TRUE)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(1,TRUE)'); + assert.strictEqual(oParser.calculate().getValue(), 0, 'Result of DAYS(1,TRUE)'); + + oParser = new parserFormula('DAYS(1,FALSE)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(1,FALSE)'); + assert.strictEqual(oParser.calculate().getValue(), 1, 'Result of DAYS(1,FALSE)'); + + oParser = new parserFormula('DAYS(TRUE,TRUE)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(TRUE,TRUE)'); + assert.strictEqual(oParser.calculate().getValue(), 0, 'Result of DAYS(TRUE,TRUE)'); + + // errors + ws.getRange2("B100").setValue("#N/A"); + ws.getRange2("B101").setValue("#NUM!"); + + oParser = new parserFormula('DAYS(#N/A,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(#N/A,10)'); + assert.strictEqual(oParser.calculate().getValue(), "#N/A", 'Result of DAYS(#N/A,10)'); + + oParser = new parserFormula('DAYS(B100,10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B100,10)'); + assert.strictEqual(oParser.calculate().getValue(), "#N/A", 'Result of DAYS(B100,10)'); + + oParser = new parserFormula('DAYS(#N/A,#NUM!)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(#N/A,#NUM!)'); + assert.strictEqual(oParser.calculate().getValue(), "#N/A", 'Result of DAYS(#N/A,#NUM!)'); + + oParser = new parserFormula('DAYS(B100,B101)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B100,B101)'); + assert.strictEqual(oParser.calculate().getValue(), "#N/A", 'Result of DAYS(B100,B101)'); + + oParser = new parserFormula('DAYS(#NUM!,#N/A)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(#NUM!,#N/A)'); + assert.strictEqual(oParser.calculate().getValue(), "#NUM!", 'Result of DAYS(#NUM!,#N/A)'); + + oParser = new parserFormula('DAYS(B101,B100)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS(B101,B100)'); + assert.strictEqual(oParser.calculate().getValue(), "#NUM!", 'Result of DAYS(B101,B100)'); + + // array + oParser = new parserFormula('DAYS({1;2;3},10)', "A1", ws); + assert.ok(oParser.parse(), 'DAYS({1;2;3},10)'); + assert.strictEqual(oParser.calculate().getValue(), -9, 'Result of DAYS({1;2;3},10)'); + + oParser = new parserFormula('DAYS({1;2;3},10)', "A1", ws); + oParser.setArrayFormulaRef(ws.getRange2("F106:I109").bbox); + assert.ok(oParser.parse(), 'DAYS({1;2;3},10)'); + array = oParser.calculate(); + assert.strictEqual(array.getElementRowCol(0, 0).getValue(), -9, 'Result of DAYS({1;2;3},10)[0,0]'); + assert.strictEqual(array.getElementRowCol(1, 0).getValue(), -8, 'Result of DAYS({1;2;3},10)[1,0]'); + assert.strictEqual(array.getElementRowCol(2, 0).getValue(), -7, 'Result of DAYS({1;2;3},10)[2,0]'); + + oParser = new parserFormula('DAYS({1;2;3},{10;9;8})', "A1", ws); + oParser.setArrayFormulaRef(ws.getRange2("F106:I109").bbox); + assert.ok(oParser.parse(), 'DAYS({1;2;3},{10;9;8})'); + array = oParser.calculate(); + assert.strictEqual(array.getElementRowCol(0, 0).getValue(), -9, 'Result of DAYS({1;2;3},{10;9;8})[0,0]'); + assert.strictEqual(array.getElementRowCol(1, 0).getValue(), -7, 'Result of DAYS({1;2;3},{10;9;8})[1,0]'); + assert.strictEqual(array.getElementRowCol(2, 0).getValue(), -5, 'Result of DAYS({1;2;3},{10;9;8})[2,0]'); + + // range + ws.getRange2("A25").setValue("1"); + ws.getRange2("A26").setValue("2"); + ws.getRange2("A27").setValue("3"); + ws.getRange2("B25").setValue("10"); + ws.getRange2("B26").setValue("9"); + ws.getRange2("B27").setValue("8"); + + oParser = new parserFormula('DAYS(A25:A27,B25:B27)', "A1", ws); + oParser.setArrayFormulaRef(ws.getRange2("F106:I109").bbox); + assert.ok(oParser.parse(), 'DAYS(A25:A27,B25:B27)'); + array = oParser.calculate(); + assert.strictEqual(array.getElementRowCol(0, 0).getValue(), -9, "Result of DAYS(A25:A27,B25:B27)[0,0]"); + assert.strictEqual(array.getElementRowCol(1, 0).getValue(), -7, "Result of DAYS(A25:A27,B25:B27)[1,0]"); + assert.strictEqual(array.getElementRowCol(2, 0).getValue(), -5, "Result of DAYS(A25:A27,B25:B27)[2,0]"); testArrayFormula2(assert, "DAYS", 2, 2); });