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

feat(formula): today function, set numfmt data #1295

Merged
merged 24 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3fdffa5
feat(formula): today function, set numfmt data
Dushusir Jan 29, 2024
8b1fd3d
feat(formula): supports numfmt
Dushusir Jan 30, 2024
149152b
test(formula): set numfmt data
Dushusir Jan 30, 2024
26a9f6e
fix(formula): sum get numfmt from link cell
Dushusir Jan 30, 2024
616d6e7
fix(sheet): recover status bar
Dushusir Jan 30, 2024
8d2c5ea
fix(formula): set numfmt on formula cell
Dushusir Jan 30, 2024
8ce958c
feat(formula): date function single number
Dushusir Jan 30, 2024
9b3a463
feat(formula): date function with array
Dushusir Jan 31, 2024
4ecdf50
fix(formula): date function test, link to formatted cell supports format
Dushusir Jan 31, 2024
de9cc3e
fix(formula): date serial calculation
Dushusir Feb 3, 2024
814be41
fix(formula): function calculate null params, abs gets 0 when linked …
Dushusir Feb 3, 2024
b6cb67b
fix(formula): concatenate calculate zero value
Dushusir Feb 3, 2024
5cc3063
fix(formula): sum,max,min .etc add blank params check
Dushusir Feb 3, 2024
8aa1fb7
test(formula): new test template
Dushusir Feb 3, 2024
bb769ba
fix(formula): date function gets error when date before 1900.1.1
Dushusir Feb 3, 2024
dc4c6bd
feat(formula): add edate function
Dushusir Feb 6, 2024
df2b6ca
test(formula): test edate function
Dushusir Feb 6, 2024
7e49aea
feat(formula): year,month,day functions
Dushusir Feb 6, 2024
9598eb5
feat(formula): match, xmatch functions
Dushusir Feb 6, 2024
ba2c693
test(formula): xmatch function test case
Dushusir Feb 6, 2024
ddebc78
test(formula): nested functions test
Dushusir Feb 6, 2024
644fbb4
fix(formula): formula cell shows format, cell calculation sets percen…
Dushusir Feb 6, 2024
28e2f49
fix(formula): edate,month,year functions support blank cell
Dushusir Feb 6, 2024
38d9310
fix(formula): xmatch description
Dushusir Feb 6, 2024
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
Prev Previous commit
Next Next commit
feat(formula): year,month,day functions
  • Loading branch information
Dushusir committed Feb 19, 2024
commit 7e49aea812ef1610a35052b5db4f89e63a6c0d4d
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, expect, it } from 'vitest';

import { FUNCTION_NAMES_DATE } from '../../function-names';
import { Day } from '..';
import { NumberValueObject } from '../../../../engine/value-object/primitive-object';
import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object';

describe('Test day function', () => {
const textFunction = new Day(FUNCTION_NAMES_DATE.DAY);

describe('Day', () => {
it('Serial number is normal', () => {
const serialNumber = new NumberValueObject(43831);
const result = textFunction.calculate(serialNumber);
expect(result.getValue()).toStrictEqual(1);
});

it('Serial number is array', () => {
const serialNumber = new ArrayValueObject({
calculateValueList: transformToValueObject([[1, ' ', 1.23, true, false, null],
[0, '100', '2.34', 'test', -3, 1900]]),
rowCount: 2,
columnCount: 6,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const result = textFunction.calculate(serialNumber);
expect(transformToValue(result.getArrayValue())).toStrictEqual([[1, '#VALUE!', 1, 1, 0, '#VALUE!'], [0, 9, 2, '#VALUE!', '#NUM!', 14]]);
});
});
});
67 changes: 67 additions & 0 deletions packages/engine-formula/src/functions/date/day/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { excelSerialToDate } from '../../../basics/date';
import { ErrorType } from '../../../basics/error-type';
import type { BaseValueObject } from '../../../engine/value-object/base-value-object';
import { ErrorValueObject } from '../../../engine/value-object/base-value-object';
import { NumberValueObject } from '../../../engine/value-object/primitive-object';
import { BaseFunction } from '../../base-function';

export class Day extends BaseFunction {
override calculate(serialNumber: BaseValueObject) {
if (serialNumber == null) {
return new ErrorValueObject(ErrorType.NA);
}

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

if (serialNumber.isArray()) {
return serialNumber.map((serialNumberObject) => {
if (serialNumberObject.isError()) {
return serialNumberObject;
}

if (serialNumberObject.isString() || serialNumberObject.isNull()) {
return new ErrorValueObject(ErrorType.VALUE);
}

const dateSerial = +serialNumberObject.getValue();

if (dateSerial < 0) {
return new ErrorValueObject(ErrorType.NUM);
}

// Excel serial 0 is 1900-01-00
// Google Sheets serial 0 is 1899-12-30
if (dateSerial === 0) {
return new NumberValueObject(0);
}

const date = excelSerialToDate(dateSerial);

const month = date.getDate();
const valueObject = new NumberValueObject(month);

return valueObject;
});
}

return new NumberValueObject(excelSerialToDate(+serialNumber.getValue()).getDate());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ describe('Test edate function', () => {
expect(transformToValue(result.getArrayValue())).toStrictEqual([[43863], [43864]]);
});

it('Start date is array with multiple format values', () => {
const startDate = new ArrayValueObject({
calculateValueList: transformToValueObject([
[1, ' ', 1.23, true, false, null],
[0, '100', '2.34', 'test', -3, 1900],
]),
rowCount: 2,
columnCount: 6,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const months = new NumberValueObject(1);
const result = textFunction.calculate(startDate, months);
expect(transformToValue(result.getArrayValue())).toStrictEqual([[32, '#VALUE!', 32, '#VALUE!', '#VALUE!', '#VALUE!'], [31, 130, 33, '#VALUE!', '#NUM!', 1931]]);
});

it('Months is array', () => {
const startDate = new NumberValueObject(43831);
const months = new ArrayValueObject({
Expand All @@ -61,5 +79,21 @@ describe('Test edate function', () => {
const result = textFunction.calculate(startDate, months);
expect(transformToValue(result.getArrayValue())).toStrictEqual([[43862], [43891]]);
});

it('Months is array with multiple format values', () => {
const startDate = new NumberValueObject(43831);
const months = new ArrayValueObject({
calculateValueList: transformToValueObject([[1, ' ', 1.23, true, false, null],
[0, '100', '2.34', 'test', -3, 1900]]),
rowCount: 2,
columnCount: 6,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const result = textFunction.calculate(startDate, months);
expect(transformToValue(result.getArrayValue())).toStrictEqual([[43862, '#VALUE!', 43862, '#VALUE!', '#VALUE!', '#VALUE!'], [43831, 46874, 43891, '#VALUE!', 43739, 101660]]);
});
});
});
26 changes: 17 additions & 9 deletions packages/engine-formula/src/functions/date/edate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import { ErrorValueObject } from '../../../engine/value-object/base-value-object
import { NumberValueObject } from '../../../engine/value-object/primitive-object';
import { BaseFunction } from '../../base-function';

/**
* TODO@Dushusir: support plaine text date: =EDATE("2020-1-1",1), =EDATE("2020/1/1",1) and other formats
*/
export class Edate extends BaseFunction {
override calculate(startDate: BaseValueObject, months: BaseValueObject) {
if (startDate == null || months == null) {
Expand All @@ -49,31 +52,36 @@ export class Edate extends BaseFunction {
months.isArray() ? (months as ArrayValueObject).getColumnCount() : 1
);

const yearArray = expandArrayValueObject(maxRowLength, maxColumnLength, startDate);
const monthArray = expandArrayValueObject(maxRowLength, maxColumnLength, months);
const startDateArray = expandArrayValueObject(maxRowLength, maxColumnLength, startDate);
const monthsArray = expandArrayValueObject(maxRowLength, maxColumnLength, months);

return yearArray.map((startDateObject, rowIndex, columnIndex) => {
const monthValueObject = monthArray.get(rowIndex, columnIndex);
return startDateArray.map((startDateObject, rowIndex, columnIndex) => {
const monthsValueObject = monthsArray.get(rowIndex, columnIndex);

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

if (monthValueObject.isError()) {
return monthValueObject;
if (monthsValueObject.isError()) {
return monthsValueObject;
}

if (startDateObject.isString() || monthValueObject.isString()) {
if (startDateObject.isString() || startDateObject.isNull() || startDateObject.isBoolean() || monthsValueObject.isString() || monthsValueObject.isNull() || monthsValueObject.isBoolean()) {
return new ErrorValueObject(ErrorType.VALUE);
}

const startDateSerial = +startDateObject.getValue();
const monthValue = Math.floor(+monthValueObject.getValue());

if (startDateSerial < 0) {
return new ErrorValueObject(ErrorType.NUM);
}

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

const startDate = excelSerialToDate(startDateSerial);

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

const resultDate = new Date(Date.UTC(year, month, day));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@
*/

import { DateFunction } from './date';
import { Day } from './day';
import { Edate } from './edate';
import { FUNCTION_NAMES_DATE } from './function-names';
import { Month } from './month';
import { Today } from './today';
import { Year } from './year';

export const functionDate = [
[Today, FUNCTION_NAMES_DATE.TODAY],
[DateFunction, FUNCTION_NAMES_DATE.DATE],
[Day, FUNCTION_NAMES_DATE.DAY],
[Edate, FUNCTION_NAMES_DATE.EDATE],
[Month, FUNCTION_NAMES_DATE.MONTH],
[Today, FUNCTION_NAMES_DATE.TODAY],
[Year, FUNCTION_NAMES_DATE.YEAR],
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, expect, it } from 'vitest';

import { FUNCTION_NAMES_DATE } from '../../function-names';
import { Month } from '..';
import { NumberValueObject } from '../../../../engine/value-object/primitive-object';
import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object';

describe('Test month function', () => {
const textFunction = new Month(FUNCTION_NAMES_DATE.MONTH);

describe('Month', () => {
it('Serial number is normal', () => {
const serialNumber = new NumberValueObject(43831);
const result = textFunction.calculate(serialNumber);
expect(result.getValue()).toStrictEqual(1);
});

it('Serial number is array', () => {
const serialNumber = new ArrayValueObject({
calculateValueList: transformToValueObject([[1, ' ', 1.23, true, false, null],
[0, '100', '2.34', 'test', -3, 1900]]),
rowCount: 2,
columnCount: 6,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const result = textFunction.calculate(serialNumber);
expect(transformToValue(result.getArrayValue())).toStrictEqual([[1, '#VALUE!', 1, 1, 1, '#VALUE!'], [1, 4, 1, '#VALUE!', '#NUM!', 3]]);
});
});
});
67 changes: 67 additions & 0 deletions packages/engine-formula/src/functions/date/month/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { excelSerialToDate } from '../../../basics/date';
import { ErrorType } from '../../../basics/error-type';
import type { BaseValueObject } from '../../../engine/value-object/base-value-object';
import { ErrorValueObject } from '../../../engine/value-object/base-value-object';
import { NumberValueObject } from '../../../engine/value-object/primitive-object';
import { BaseFunction } from '../../base-function';

export class Month extends BaseFunction {
override calculate(serialNumber: BaseValueObject) {
if (serialNumber == null) {
return new ErrorValueObject(ErrorType.NA);
}

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

if (serialNumber.isArray()) {
return serialNumber.map((serialNumberObject) => {
if (serialNumberObject.isError()) {
return serialNumberObject;
}

if (serialNumberObject.isString() || serialNumberObject.isNull()) {
return new ErrorValueObject(ErrorType.VALUE);
}

const dateSerial = +serialNumberObject.getValue();

if (dateSerial < 0) {
return new ErrorValueObject(ErrorType.NUM);
}

// Excel serial 0 is 1900-01-00
// Google Sheets serial 0 is 1899-12-30
if (dateSerial === 0) {
return new NumberValueObject(1);
}

const date = excelSerialToDate(dateSerial);

const month = date.getUTCMonth() + 1;
const valueObject = new NumberValueObject(month);

return valueObject;
});
}

return new NumberValueObject(excelSerialToDate(+serialNumber.getValue()).getUTCMonth() + 1);
}
}
Loading