@odoo/o-spreadsheet 14.0.1 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o_spreadsheet.cjs.js +31302 -0
- package/dist/o_spreadsheet.d.ts +6604 -0
- package/dist/o_spreadsheet.esm.js +31257 -0
- package/dist/o_spreadsheet.iife.js +31304 -0
- package/dist/o_spreadsheet.iife.min.js +3071 -0
- package/package.json +57 -15
- package/.eslintrc.json +0 -20
- package/.husky/post-checkout +0 -9
- package/.husky/pre-commit +0 -39
- package/.prettierignore +0 -1
- package/astToFormula.patch +0 -0
- package/demo/data.js +0 -255
- package/demo/index.html +0 -9
- package/demo/libs/Chart.bundle.js +0 -20755
- package/demo/main.js +0 -101
- package/doc/readme.md +0 -46
- package/rollup.config.js +0 -23
- package/src/base_plugin.ts +0 -102
- package/src/components/autofill.ts +0 -146
- package/src/components/bottom_bar.ts +0 -199
- package/src/components/color_picker.ts +0 -150
- package/src/components/composer/autocomplete_dropdown.ts +0 -135
- package/src/components/composer/composer.ts +0 -487
- package/src/components/composer/content_editable_helper.ts +0 -146
- package/src/components/figures/chart.ts +0 -70
- package/src/components/figures/container.ts +0 -268
- package/src/components/figures/text_figure.ts +0 -36
- package/src/components/grid.ts +0 -635
- package/src/components/helpers/dom_helpers.ts +0 -7
- package/src/components/helpers/drag_and_drop.ts +0 -17
- package/src/components/icons.ts +0 -36
- package/src/components/index.ts +0 -1
- package/src/components/menu.ts +0 -288
- package/src/components/overlay.ts +0 -457
- package/src/components/scrollbar.ts +0 -22
- package/src/components/selection_input.ts +0 -168
- package/src/components/side_panel/cell_is_rule_editor.ts +0 -169
- package/src/components/side_panel/chart_panel.ts +0 -104
- package/src/components/side_panel/color_scale_rule_editor.ts +0 -145
- package/src/components/side_panel/conditional_formatting.ts +0 -396
- package/src/components/side_panel/side_panel.ts +0 -127
- package/src/components/side_panel/translations_terms.ts +0 -45
- package/src/components/spreadsheet.ts +0 -198
- package/src/components/top_bar.ts +0 -535
- package/src/constants.ts +0 -26
- package/src/data.ts +0 -149
- package/src/fonts.ts +0 -41
- package/src/formulas/compiler.ts +0 -258
- package/src/formulas/composer_tokenizer.ts +0 -70
- package/src/formulas/index.ts +0 -15
- package/src/formulas/normalize.ts +0 -52
- package/src/formulas/parser.ts +0 -280
- package/src/formulas/range_tokenizer.ts +0 -97
- package/src/formulas/tokenizer.ts +0 -242
- package/src/functions/arguments.ts +0 -114
- package/src/functions/dates.ts +0 -302
- package/src/functions/helpers.ts +0 -592
- package/src/functions/index.ts +0 -52
- package/src/functions/module_database.ts +0 -282
- package/src/functions/module_date.ts +0 -743
- package/src/functions/module_info.ts +0 -69
- package/src/functions/module_logical.ts +0 -208
- package/src/functions/module_lookup.ts +0 -185
- package/src/functions/module_math.ts +0 -1252
- package/src/functions/module_operators.ts +0 -291
- package/src/functions/module_statistical.ts +0 -882
- package/src/functions/module_text.ts +0 -370
- package/src/helpers/color.ts +0 -30
- package/src/helpers/coordinates.ts +0 -71
- package/src/helpers/grid_manipulation.ts +0 -68
- package/src/helpers/index.ts +0 -7
- package/src/helpers/misc.ts +0 -76
- package/src/helpers/numbers.ts +0 -117
- package/src/helpers/uuid.ts +0 -19
- package/src/helpers/zones.ts +0 -263
- package/src/history.ts +0 -186
- package/src/index.ts +0 -84
- package/src/model.ts +0 -261
- package/src/plugins/autofill.ts +0 -412
- package/src/plugins/chart.ts +0 -404
- package/src/plugins/clipboard.ts +0 -461
- package/src/plugins/conditional_format.ts +0 -445
- package/src/plugins/core.ts +0 -1502
- package/src/plugins/edition.ts +0 -157
- package/src/plugins/evaluation.ts +0 -428
- package/src/plugins/figures.ts +0 -123
- package/src/plugins/formatting.ts +0 -630
- package/src/plugins/highlight.ts +0 -187
- package/src/plugins/index.ts +0 -32
- package/src/plugins/merge.ts +0 -524
- package/src/plugins/renderer.ts +0 -571
- package/src/plugins/selection.ts +0 -562
- package/src/plugins/selection_inputs.ts +0 -326
- package/src/registries/autofill_modifiers.ts +0 -76
- package/src/registries/autofill_rules.ts +0 -98
- package/src/registries/figure_registry.ts +0 -30
- package/src/registries/index.ts +0 -7
- package/src/registries/menu_items_registry.ts +0 -110
- package/src/registries/menus/cell_menu_registry.ts +0 -79
- package/src/registries/menus/col_menu_registry.ts +0 -63
- package/src/registries/menus/index.ts +0 -6
- package/src/registries/menus/menu_items_actions.ts +0 -425
- package/src/registries/menus/row_menu_registry.ts +0 -63
- package/src/registries/menus/sheet_menu_registry.ts +0 -75
- package/src/registries/menus/topbar_menu_registry.ts +0 -204
- package/src/registries/side_panel_registry.ts +0 -26
- package/src/registries/topbar_component_registry.ts +0 -12
- package/src/registry.ts +0 -51
- package/src/translation.ts +0 -44
- package/src/types/autofill.ts +0 -48
- package/src/types/chart.ts +0 -26
- package/src/types/commands.ts +0 -716
- package/src/types/conditional_formatting.ts +0 -124
- package/src/types/env.ts +0 -13
- package/src/types/functions.ts +0 -35
- package/src/types/getters.ts +0 -103
- package/src/types/index.ts +0 -20
- package/src/types/misc.ts +0 -143
- package/src/types/rendering.ts +0 -41
- package/src/types/workbook_data.ts +0 -62
- package/tests/__mocks__/uuid.ts +0 -7
- package/tests/canvas.mock.ts +0 -34
- package/tests/components/__mocks__/content_editable_helper.ts +0 -79
- package/tests/components/__mocks__/scrollbar.ts +0 -18
- package/tests/components/__snapshots__/autocomplete_dropdown_test.ts.snap +0 -29
- package/tests/components/__snapshots__/bottom_bar_test.ts.snap +0 -75
- package/tests/components/__snapshots__/context_menu_test.ts.snap +0 -88
- package/tests/components/__snapshots__/grid_test.ts.snap +0 -60
- package/tests/components/__snapshots__/spreadsheet_test.ts.snap +0 -455
- package/tests/components/__snapshots__/top_bar_test.ts.snap +0 -705
- package/tests/components/autocomplete_dropdown_test.ts +0 -315
- package/tests/components/autofill_test.ts +0 -167
- package/tests/components/bottom_bar_test.ts +0 -262
- package/tests/components/chart_side_panel_test.ts +0 -123
- package/tests/components/composer_test.ts +0 -400
- package/tests/components/context_menu_test.ts +0 -825
- package/tests/components/grid_manipulation_test.ts +0 -163
- package/tests/components/grid_test.ts +0 -581
- package/tests/components/overlay_test.ts +0 -541
- package/tests/components/selection_input_test.ts +0 -259
- package/tests/components/side_panel_test.ts +0 -148
- package/tests/components/spreadsheet_test.ts +0 -194
- package/tests/components/top_bar_test.ts +0 -427
- package/tests/data_test.ts +0 -175
- package/tests/dom_helper.ts +0 -42
- package/tests/formulas/__snapshots__/compiler_test.ts.snap +0 -302
- package/tests/formulas/compiler_test.ts +0 -266
- package/tests/formulas/composer_tokenizer_test.ts +0 -137
- package/tests/formulas/expressions_test.ts +0 -57
- package/tests/formulas/formulas_test.ts +0 -80
- package/tests/formulas/normalize_test.ts +0 -82
- package/tests/formulas/parser_test.ts +0 -224
- package/tests/formulas/range_tokenizer_test.ts +0 -187
- package/tests/formulas/tokenizer_test.ts +0 -164
- package/tests/functions/arguments_test.ts +0 -141
- package/tests/functions/dates_test.ts +0 -1081
- package/tests/functions/functions_test.ts +0 -53
- package/tests/functions/helper_test.ts +0 -98
- package/tests/functions/module_database_test.ts +0 -311
- package/tests/functions/module_date_test.ts +0 -941
- package/tests/functions/module_info_test.ts +0 -139
- package/tests/functions/module_logical_test.ts +0 -369
- package/tests/functions/module_lookup_test.ts +0 -541
- package/tests/functions/module_math_test.ts +0 -2482
- package/tests/functions/module_operators_test.ts +0 -955
- package/tests/functions/module_statistical_test.ts +0 -2014
- package/tests/functions/module_text_test.ts +0 -667
- package/tests/helpers/coordinates_test.ts +0 -25
- package/tests/helpers/misc_test.ts +0 -95
- package/tests/helpers/numbers_test.ts +0 -196
- package/tests/helpers/zones_test.ts +0 -97
- package/tests/helpers.ts +0 -384
- package/tests/menu_items_registry_test.ts +0 -540
- package/tests/model/plugins/__snapshots__/chart_test.ts.snap +0 -90
- package/tests/model/plugins/chart_test.ts +0 -562
- package/tests/model_test.ts +0 -82
- package/tests/plugins/__snapshots__/conditional_formatting_test.ts.snap +0 -131
- package/tests/plugins/__snapshots__/renderer_test.ts.snap +0 -371
- package/tests/plugins/autofill_test.ts +0 -457
- package/tests/plugins/borders_test.ts +0 -295
- package/tests/plugins/clipboard_test.ts +0 -1180
- package/tests/plugins/conditional_formatting_test.ts +0 -1253
- package/tests/plugins/core_test.ts +0 -614
- package/tests/plugins/edition_test.ts +0 -100
- package/tests/plugins/evaluation_async_test.ts +0 -332
- package/tests/plugins/evaluation_dates_test.ts +0 -79
- package/tests/plugins/evaluation_test.ts +0 -901
- package/tests/plugins/figures_test.ts +0 -327
- package/tests/plugins/formatting_test.ts +0 -391
- package/tests/plugins/grid_manipulation_test.ts +0 -1366
- package/tests/plugins/highlight_test.ts +0 -413
- package/tests/plugins/history_test.ts +0 -142
- package/tests/plugins/import_export_test.ts +0 -276
- package/tests/plugins/merges_test.ts +0 -490
- package/tests/plugins/navigation_test.ts +0 -181
- package/tests/plugins/plugins/evaluation_test.ts +0 -111
- package/tests/plugins/renderer_test.ts +0 -598
- package/tests/plugins/resizing_test.ts +0 -152
- package/tests/plugins/selection_input_test.ts +0 -409
- package/tests/plugins/selection_test.ts +0 -442
- package/tests/plugins/sheets_test.ts +0 -643
- package/tests/plugins/style_test.ts +0 -90
- package/tsconfig.json +0 -22
|
@@ -1,743 +0,0 @@
|
|
|
1
|
-
import { InternalDate, parseDateTime, toNativeDate } from "../functions/dates";
|
|
2
|
-
import { _lt } from "../translation";
|
|
3
|
-
import { FunctionDescription } from "../types";
|
|
4
|
-
import { args } from "./arguments";
|
|
5
|
-
import { toNumber, toString, visitAny } from "./helpers";
|
|
6
|
-
|
|
7
|
-
const INITIAL_1900_DAY = new Date(1899, 11, 30);
|
|
8
|
-
|
|
9
|
-
// -----------------------------------------------------------------------------
|
|
10
|
-
// DATE
|
|
11
|
-
// -----------------------------------------------------------------------------
|
|
12
|
-
export const DATE: FunctionDescription = {
|
|
13
|
-
description: _lt("Converts year/month/day into a date."),
|
|
14
|
-
args: args(`
|
|
15
|
-
year (number) ${_lt("The year component of the date.")}")}
|
|
16
|
-
month (number) ${_lt("The month component of the date.")}")}
|
|
17
|
-
day (number) ${_lt("The day component of the date.")}")}
|
|
18
|
-
`),
|
|
19
|
-
returns: ["DATE"],
|
|
20
|
-
compute: function (year: any, month: any, day: any): InternalDate {
|
|
21
|
-
let _year = Math.trunc(toNumber(year));
|
|
22
|
-
const _month = Math.trunc(toNumber(month));
|
|
23
|
-
const _day = Math.trunc(toNumber(day));
|
|
24
|
-
|
|
25
|
-
// For years less than 0 or greater than 10000, return #ERROR.
|
|
26
|
-
if (_year < 0 || 10000 <= _year) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
_lt(`function DATE parameter year should be greater or equal to 0 and lesser than 10000.`)
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Between 0 and 1899, we add that value to 1900 to calculate the year
|
|
33
|
-
if (_year < 1900) {
|
|
34
|
-
_year += 1900;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const jsDate = new Date(_year, _month - 1, _day);
|
|
38
|
-
const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
|
|
39
|
-
|
|
40
|
-
if (delta < 0) {
|
|
41
|
-
throw new Error(_lt(`function DATE result should not be lesser than 01/01/1900`));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
value: Math.round(delta / 86400000),
|
|
46
|
-
format: "m/d/yyyy",
|
|
47
|
-
jsDate: jsDate,
|
|
48
|
-
};
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// -----------------------------------------------------------------------------
|
|
53
|
-
// DATEVALUE
|
|
54
|
-
// -----------------------------------------------------------------------------
|
|
55
|
-
export const DATEVALUE: FunctionDescription = {
|
|
56
|
-
description: _lt("Converts a date string to a date value."),
|
|
57
|
-
args: args(`
|
|
58
|
-
date_string (string) ${_lt("The string representing the date.")}
|
|
59
|
-
`),
|
|
60
|
-
returns: ["NUMBER"],
|
|
61
|
-
compute: function (date_string: any): number {
|
|
62
|
-
const _dateString = toString(date_string);
|
|
63
|
-
const datetime = parseDateTime(_dateString);
|
|
64
|
-
if (datetime === null) {
|
|
65
|
-
throw new Error(_lt("DATEVALUE parameter '%s' cannot be parsed to date/time.", _dateString));
|
|
66
|
-
}
|
|
67
|
-
return Math.trunc(datetime.value);
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// -----------------------------------------------------------------------------
|
|
72
|
-
// DAY
|
|
73
|
-
// -----------------------------------------------------------------------------
|
|
74
|
-
export const DAY: FunctionDescription = {
|
|
75
|
-
description: _lt("Day of the month that a specific date falls on."),
|
|
76
|
-
args: args(`
|
|
77
|
-
date (string) ${_lt("The date from which to extract the day.")}
|
|
78
|
-
`),
|
|
79
|
-
returns: ["NUMBER"],
|
|
80
|
-
compute: function (date: any): number {
|
|
81
|
-
return toNativeDate(date).getDate();
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// -----------------------------------------------------------------------------
|
|
86
|
-
// DAYS
|
|
87
|
-
// -----------------------------------------------------------------------------
|
|
88
|
-
export const DAYS: FunctionDescription = {
|
|
89
|
-
description: _lt("Number of days between two dates."),
|
|
90
|
-
args: args(`
|
|
91
|
-
end_date (date) ${_lt("The end of the date range.")}
|
|
92
|
-
start_date (date) ${_lt("The start of the date range.")}
|
|
93
|
-
`),
|
|
94
|
-
returns: ["NUMBER"],
|
|
95
|
-
compute: function (end_date: any, start_date: any): number {
|
|
96
|
-
const _endDate = toNativeDate(end_date);
|
|
97
|
-
const _startDate = toNativeDate(start_date);
|
|
98
|
-
const dateDif = _endDate.getTime() - _startDate.getTime();
|
|
99
|
-
return Math.round(dateDif / 86400000);
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// -----------------------------------------------------------------------------
|
|
104
|
-
// EDATE
|
|
105
|
-
// -----------------------------------------------------------------------------
|
|
106
|
-
export const EDATE: FunctionDescription = {
|
|
107
|
-
description: _lt("Date a number of months before/after another date."),
|
|
108
|
-
args: args(`
|
|
109
|
-
start_date (date) ${_lt("The date from which to calculate the result.")}
|
|
110
|
-
months (number) ${_lt(
|
|
111
|
-
"The number of months before (negative) or after (positive) 'start_date' to calculate."
|
|
112
|
-
)}
|
|
113
|
-
`),
|
|
114
|
-
returns: ["DATE"],
|
|
115
|
-
compute: function (start_date: any, months: any): InternalDate {
|
|
116
|
-
const _startDate = toNativeDate(start_date);
|
|
117
|
-
const _months = Math.trunc(toNumber(months));
|
|
118
|
-
|
|
119
|
-
const yStart = _startDate.getFullYear();
|
|
120
|
-
const mStart = _startDate.getMonth();
|
|
121
|
-
const dStart = _startDate.getDate();
|
|
122
|
-
const jsDate = new Date(yStart, mStart + _months, dStart);
|
|
123
|
-
const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
value: Math.round(delta / 86400000),
|
|
127
|
-
format: "m/d/yyyy",
|
|
128
|
-
jsDate: jsDate,
|
|
129
|
-
};
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
// -----------------------------------------------------------------------------
|
|
134
|
-
// EOMONTH
|
|
135
|
-
// -----------------------------------------------------------------------------
|
|
136
|
-
export const EOMONTH: FunctionDescription = {
|
|
137
|
-
description: _lt("Last day of a month before or after a date."),
|
|
138
|
-
args: args(`
|
|
139
|
-
start_date (date) ${_lt("The date from which to calculate the result.")}
|
|
140
|
-
months (number) ${_lt(
|
|
141
|
-
"The number of months before (negative) or after (positive) 'start_date' to consider."
|
|
142
|
-
)}
|
|
143
|
-
`),
|
|
144
|
-
returns: ["DATE"],
|
|
145
|
-
compute: function (start_date: any, months: any): InternalDate {
|
|
146
|
-
const _startDate = toNativeDate(start_date);
|
|
147
|
-
const _months = Math.trunc(toNumber(months));
|
|
148
|
-
|
|
149
|
-
const yStart = _startDate.getFullYear();
|
|
150
|
-
const mStart = _startDate.getMonth();
|
|
151
|
-
const jsDate = new Date(yStart, mStart + _months + 1, 0);
|
|
152
|
-
const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
value: Math.round(delta / 86400000),
|
|
156
|
-
format: "m/d/yyyy",
|
|
157
|
-
jsDate: jsDate,
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
// -----------------------------------------------------------------------------
|
|
163
|
-
// HOUR
|
|
164
|
-
// -----------------------------------------------------------------------------
|
|
165
|
-
export const HOUR: FunctionDescription = {
|
|
166
|
-
description: _lt("Hour component of a specific time."),
|
|
167
|
-
args: args(`
|
|
168
|
-
time (date) ${_lt("The time from which to calculate the hour component.")}
|
|
169
|
-
`),
|
|
170
|
-
returns: ["NUMBER"],
|
|
171
|
-
compute: function (date: any): number {
|
|
172
|
-
return toNativeDate(date).getHours();
|
|
173
|
-
},
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// -----------------------------------------------------------------------------
|
|
177
|
-
// ISOWEEKNUM
|
|
178
|
-
// -----------------------------------------------------------------------------
|
|
179
|
-
export const ISOWEEKNUM: FunctionDescription = {
|
|
180
|
-
description: _lt("ISO week number of the year."),
|
|
181
|
-
args: args(`
|
|
182
|
-
date (date) ${_lt(
|
|
183
|
-
"The date for which to determine the ISO week number. Must be a reference to a cell containing a date, a function returning a date type, or a number."
|
|
184
|
-
)}
|
|
185
|
-
`),
|
|
186
|
-
returns: ["NUMBER"],
|
|
187
|
-
compute: function (date: any): number {
|
|
188
|
-
const _date = toNativeDate(date);
|
|
189
|
-
const y = _date.getFullYear();
|
|
190
|
-
|
|
191
|
-
// 1 - As the 1st week of a year can start the previous year or after the 1st
|
|
192
|
-
// january we first look if the date is in the weeks of the current year, previous
|
|
193
|
-
// year or year after.
|
|
194
|
-
|
|
195
|
-
// A - We look for the current year, the first days of the first week
|
|
196
|
-
// and the last days of the last week
|
|
197
|
-
|
|
198
|
-
// The first week of the year is the week that contains the first
|
|
199
|
-
// Thursday of the year.
|
|
200
|
-
|
|
201
|
-
let firstThursday = 1;
|
|
202
|
-
while (new Date(y, 0, firstThursday).getDay() !== 4) {
|
|
203
|
-
firstThursday += 1;
|
|
204
|
-
}
|
|
205
|
-
const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
|
|
206
|
-
|
|
207
|
-
// The last week of the year is the week that contains the last Thursday of
|
|
208
|
-
// the year.
|
|
209
|
-
|
|
210
|
-
let lastThursday = 31;
|
|
211
|
-
while (new Date(y, 11, lastThursday).getDay() !== 4) {
|
|
212
|
-
lastThursday -= 1;
|
|
213
|
-
}
|
|
214
|
-
const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
|
|
215
|
-
|
|
216
|
-
// B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
|
|
217
|
-
// If our date < firstDayOfFirstWeek then it's in the weeks of the year before
|
|
218
|
-
|
|
219
|
-
let offsetYear;
|
|
220
|
-
if (firstDayOfFirstWeek.getTime() <= _date.getTime()) {
|
|
221
|
-
if (_date.getTime() <= lastDayOfLastWeek.getTime()) {
|
|
222
|
-
offsetYear = 0;
|
|
223
|
-
} else {
|
|
224
|
-
offsetYear = 1;
|
|
225
|
-
}
|
|
226
|
-
} else {
|
|
227
|
-
offsetYear = -1;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// 2 - now that the year is known, we are looking at the difference between
|
|
231
|
-
// the first day of this year and the date. The difference in days divided by
|
|
232
|
-
// 7 gives us the week number
|
|
233
|
-
|
|
234
|
-
let firstDay;
|
|
235
|
-
switch (offsetYear) {
|
|
236
|
-
case 0:
|
|
237
|
-
firstDay = firstDayOfFirstWeek;
|
|
238
|
-
break;
|
|
239
|
-
case 1:
|
|
240
|
-
// firstDay is the 1st day of the 1st week of the year after
|
|
241
|
-
// firstDay = lastDayOfLastWeek + 1 Day
|
|
242
|
-
firstDay = new Date(y, 11, lastThursday + 3 + 1);
|
|
243
|
-
break;
|
|
244
|
-
case -1:
|
|
245
|
-
// firstDay is the 1st day of the 1st week of the previous year.
|
|
246
|
-
// The first week of the previous year is the week that contains the
|
|
247
|
-
// first Thursday of the previous year.
|
|
248
|
-
let firstThursdayPreviousYear = 1;
|
|
249
|
-
while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
|
|
250
|
-
firstThursdayPreviousYear += 1;
|
|
251
|
-
}
|
|
252
|
-
firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const dif = (_date.getTime() - firstDay.getTime()) / 86400000;
|
|
257
|
-
return Math.floor(dif / 7) + 1;
|
|
258
|
-
},
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// -----------------------------------------------------------------------------
|
|
262
|
-
// MINUTE
|
|
263
|
-
// -----------------------------------------------------------------------------
|
|
264
|
-
export const MINUTE: FunctionDescription = {
|
|
265
|
-
description: _lt("Minute component of a specific time."),
|
|
266
|
-
args: args(`
|
|
267
|
-
time (date) ${_lt("The time from which to calculate the minute component.")}
|
|
268
|
-
`),
|
|
269
|
-
returns: ["NUMBER"],
|
|
270
|
-
compute: function (date: any): number {
|
|
271
|
-
return toNativeDate(date).getMinutes();
|
|
272
|
-
},
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// -----------------------------------------------------------------------------
|
|
276
|
-
// MONTH
|
|
277
|
-
// -----------------------------------------------------------------------------
|
|
278
|
-
export const MONTH: FunctionDescription = {
|
|
279
|
-
description: _lt("Month of the year a specific date falls in"),
|
|
280
|
-
args: args(`
|
|
281
|
-
date (date) ${_lt("The date from which to extract the month.")}
|
|
282
|
-
`),
|
|
283
|
-
returns: ["NUMBER"],
|
|
284
|
-
compute: function (date: any): number {
|
|
285
|
-
return toNativeDate(date).getMonth() + 1;
|
|
286
|
-
},
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
// -----------------------------------------------------------------------------
|
|
290
|
-
// NETWORKDAYS
|
|
291
|
-
// -----------------------------------------------------------------------------
|
|
292
|
-
export const NETWORKDAYS: FunctionDescription = {
|
|
293
|
-
description: _lt("Net working days between two provided days."),
|
|
294
|
-
args: args(`
|
|
295
|
-
start_date (date) ${_lt(
|
|
296
|
-
"The start date of the period from which to calculate the number of net working days."
|
|
297
|
-
)}
|
|
298
|
-
end_date (date) ${_lt(
|
|
299
|
-
"The end date of the period from which to calculate the number of net working days."
|
|
300
|
-
)}
|
|
301
|
-
holidays (date, range<date>, optional) ${_lt(
|
|
302
|
-
"A range or array constant containing the date serial numbers to consider holidays."
|
|
303
|
-
)}
|
|
304
|
-
`),
|
|
305
|
-
returns: ["NUMBER"],
|
|
306
|
-
compute: function (start_date: any, end_date: any, holidays: any): number {
|
|
307
|
-
return NETWORKDAYS_INTL.compute(start_date, end_date, 1, holidays);
|
|
308
|
-
},
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
// -----------------------------------------------------------------------------
|
|
312
|
-
// NETWORKDAYS.INTL
|
|
313
|
-
// -----------------------------------------------------------------------------
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Transform weekend Spreadsheet informations into Date Day JavaScript informations.
|
|
317
|
-
* Take string (String method) or number (Number method), return array of numbers.
|
|
318
|
-
*
|
|
319
|
-
* String method: weekends can be specified using seven 0’s and 1’s, where the
|
|
320
|
-
* first number in the set represents Monday and the last number is for Sunday.
|
|
321
|
-
* A zero means that the day is a work day, a 1 means that the day is a weekend.
|
|
322
|
-
* For example, “0000011” would mean Saturday and Sunday are weekends.
|
|
323
|
-
*
|
|
324
|
-
* Number method: instead of using the string method above, a single number can
|
|
325
|
-
* be used. 1 = Saturday/Sunday are weekends, 2 = Sunday/Monday, and this pattern
|
|
326
|
-
* repeats until 7 = Friday/Saturday. 11 = Sunday is the only weekend, 12 = Monday
|
|
327
|
-
* is the only weekend, and this pattern repeats until 17 = Saturday is the only
|
|
328
|
-
* weekend.
|
|
329
|
-
*
|
|
330
|
-
* Exemple:
|
|
331
|
-
* - 11 return [0] (correspond to Sunday)
|
|
332
|
-
* - 12 return [1] (correspond to Monday)
|
|
333
|
-
* - 3 return [1,2] (correspond to Monday and Tuesday)
|
|
334
|
-
* - "0101010" return [2,4,6] (correspond to Tuesday, Thursday and Saturday)
|
|
335
|
-
*/
|
|
336
|
-
function weekendToDayNumber(weekend: any): number[] {
|
|
337
|
-
if (typeof weekend === "string") {
|
|
338
|
-
let result: number[] = [];
|
|
339
|
-
|
|
340
|
-
if (weekend.length === 7) {
|
|
341
|
-
for (let i = 0; i < 7; i++) {
|
|
342
|
-
switch (weekend.charAt(i)) {
|
|
343
|
-
case "0":
|
|
344
|
-
break;
|
|
345
|
-
case "1":
|
|
346
|
-
// "1000000" corespond to Monday [1]
|
|
347
|
-
// "0000010" corespond to Saturday [6]
|
|
348
|
-
// "0000001" corespond to Sunday [0]
|
|
349
|
-
result.push(i + 1 === 7 ? 0 : i + 1);
|
|
350
|
-
break;
|
|
351
|
-
default:
|
|
352
|
-
throw new Error(
|
|
353
|
-
_lt(
|
|
354
|
-
"Function [[FUNCTION_NAME]] parameter 3 requires a string composed of 0 or 1. Actual string is '%s'.",
|
|
355
|
-
weekend
|
|
356
|
-
)
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return result;
|
|
361
|
-
}
|
|
362
|
-
throw new Error(
|
|
363
|
-
_lt(
|
|
364
|
-
"Function [[FUNCTION_NAME]] parameter 3 requires a string with 7 characters. Actual string is '%s'.",
|
|
365
|
-
weekend
|
|
366
|
-
)
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (typeof weekend === "number") {
|
|
371
|
-
if (1 <= weekend && weekend <= 7) {
|
|
372
|
-
// 1 = Saturday/Sunday are weekends
|
|
373
|
-
// 2 = Sunday/Monday
|
|
374
|
-
// ...
|
|
375
|
-
// 7 = Friday/Saturday.
|
|
376
|
-
return [weekend - 2 === -1 ? 6 : weekend - 2, weekend - 1];
|
|
377
|
-
}
|
|
378
|
-
if (11 <= weekend && weekend <= 17) {
|
|
379
|
-
// 11 = Sunday is the only weekend
|
|
380
|
-
// 12 = Monday is the only weekend
|
|
381
|
-
// ...
|
|
382
|
-
// 17 = Saturday is the only weekend.
|
|
383
|
-
return [weekend - 11];
|
|
384
|
-
}
|
|
385
|
-
throw new Error(
|
|
386
|
-
_lt(
|
|
387
|
-
"Function [[FUNCTION_NAME]] parameter 3 requires a string or a number in the range 1-7 or 11-17. Actual number is %s.",
|
|
388
|
-
weekend.toString()
|
|
389
|
-
)
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
throw new Error(_lt(`Function [[FUNCTION_NAME]] parameter 3 requires a number or a string.`));
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
export const NETWORKDAYS_INTL: FunctionDescription = {
|
|
397
|
-
description: _lt("Net working days between two dates (specifying weekends)."),
|
|
398
|
-
args: args(`
|
|
399
|
-
start_date (date) ${_lt(
|
|
400
|
-
"The start date of the period from which to calculate the number of net working days."
|
|
401
|
-
)}
|
|
402
|
-
end_date (date) ${_lt(
|
|
403
|
-
"The end date of the period from which to calculate the number of net working days."
|
|
404
|
-
)}
|
|
405
|
-
weekend (any, optional, default=1) ${_lt(
|
|
406
|
-
"A number or string representing which days of the week are considered weekends."
|
|
407
|
-
)}
|
|
408
|
-
holidays (date, range<date>, optional) ${_lt(
|
|
409
|
-
"A range or array constant containing the dates to consider as holidays."
|
|
410
|
-
)}
|
|
411
|
-
`),
|
|
412
|
-
returns: ["NUMBER"],
|
|
413
|
-
compute: function (
|
|
414
|
-
start_date: any,
|
|
415
|
-
end_date: any,
|
|
416
|
-
weekend: any = 1,
|
|
417
|
-
holidays: any = undefined
|
|
418
|
-
): number {
|
|
419
|
-
const _startDate = toNativeDate(start_date);
|
|
420
|
-
const _endDate = toNativeDate(end_date);
|
|
421
|
-
|
|
422
|
-
const daysWeekend = weekendToDayNumber(weekend);
|
|
423
|
-
let timesHoliday = new Set();
|
|
424
|
-
if (holidays !== undefined) {
|
|
425
|
-
visitAny(holidays, (h) => {
|
|
426
|
-
const holiday = toNativeDate(h);
|
|
427
|
-
timesHoliday.add(holiday.getTime());
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
const invertDate = _startDate.getTime() > _endDate.getTime();
|
|
432
|
-
const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
|
|
433
|
-
let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
|
|
434
|
-
const timeStopDate = stopDate.getTime();
|
|
435
|
-
let timeStepDate = stepDate.getTime();
|
|
436
|
-
|
|
437
|
-
let netWorkingDay = 0;
|
|
438
|
-
|
|
439
|
-
while (timeStepDate <= timeStopDate) {
|
|
440
|
-
if (!daysWeekend.includes(stepDate.getDay()) && !timesHoliday.has(timeStepDate)) {
|
|
441
|
-
netWorkingDay += 1;
|
|
442
|
-
}
|
|
443
|
-
stepDate.setDate(stepDate.getDate() + 1);
|
|
444
|
-
timeStepDate = stepDate.getTime();
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return invertDate ? -netWorkingDay : netWorkingDay;
|
|
448
|
-
},
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
// -----------------------------------------------------------------------------
|
|
452
|
-
// NOW
|
|
453
|
-
// -----------------------------------------------------------------------------
|
|
454
|
-
|
|
455
|
-
export const NOW: FunctionDescription = {
|
|
456
|
-
description: _lt("Current date and time as a date value."),
|
|
457
|
-
args: [],
|
|
458
|
-
returns: ["DATE"],
|
|
459
|
-
compute: function (): InternalDate {
|
|
460
|
-
let today = new Date();
|
|
461
|
-
today.setMilliseconds(0);
|
|
462
|
-
const delta = today.getTime() - INITIAL_1900_DAY.getTime();
|
|
463
|
-
const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
|
|
464
|
-
return {
|
|
465
|
-
value: Math.floor(delta / 86400000) + time,
|
|
466
|
-
format: "m/d/yyyy hh:mm:ss",
|
|
467
|
-
jsDate: today,
|
|
468
|
-
};
|
|
469
|
-
},
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
// -----------------------------------------------------------------------------
|
|
473
|
-
// SECOND
|
|
474
|
-
// -----------------------------------------------------------------------------
|
|
475
|
-
export const SECOND: FunctionDescription = {
|
|
476
|
-
description: _lt("Minute component of a specific time."),
|
|
477
|
-
args: args(`
|
|
478
|
-
time (date) ${_lt("The time from which to calculate the second component.")}
|
|
479
|
-
`),
|
|
480
|
-
returns: ["NUMBER"],
|
|
481
|
-
compute: function (date: any): number {
|
|
482
|
-
return toNativeDate(date).getSeconds();
|
|
483
|
-
},
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
// -----------------------------------------------------------------------------
|
|
487
|
-
// TIME
|
|
488
|
-
// -----------------------------------------------------------------------------
|
|
489
|
-
export const TIME: FunctionDescription = {
|
|
490
|
-
description: _lt("Converts hour/minute/second into a time."),
|
|
491
|
-
args: args(`
|
|
492
|
-
hour (number) ${_lt("The hour component of the time.")}
|
|
493
|
-
minute (number) ${_lt("The minute component of the time.")}
|
|
494
|
-
second (number) ${_lt("The second component of the time.")}
|
|
495
|
-
`),
|
|
496
|
-
returns: ["DATE"],
|
|
497
|
-
compute: function (hour: any, minute: any, second: any): InternalDate {
|
|
498
|
-
let _hour = Math.trunc(toNumber(hour));
|
|
499
|
-
let _minute = Math.trunc(toNumber(minute));
|
|
500
|
-
let _second = Math.trunc(toNumber(second));
|
|
501
|
-
|
|
502
|
-
_minute += Math.floor(_second / 60);
|
|
503
|
-
_second = (_second % 60) + (_second < 0 ? 60 : 0);
|
|
504
|
-
|
|
505
|
-
_hour += Math.floor(_minute / 60);
|
|
506
|
-
_minute = (_minute % 60) + (_minute < 0 ? 60 : 0);
|
|
507
|
-
|
|
508
|
-
_hour %= 24;
|
|
509
|
-
|
|
510
|
-
if (_hour < 0) {
|
|
511
|
-
throw new Error(_lt(`function Time result should not be negative`));
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const jsDate = new Date(1899, 11, 30, _hour, _minute, _second);
|
|
515
|
-
|
|
516
|
-
return {
|
|
517
|
-
value: _hour / 24 + _minute / (24 * 60) + _second / (24 * 60 * 60),
|
|
518
|
-
format: "hh:mm:ss a",
|
|
519
|
-
jsDate: jsDate,
|
|
520
|
-
};
|
|
521
|
-
},
|
|
522
|
-
};
|
|
523
|
-
|
|
524
|
-
// -----------------------------------------------------------------------------
|
|
525
|
-
// TIMEVALUE
|
|
526
|
-
// -----------------------------------------------------------------------------
|
|
527
|
-
export const TIMEVALUE: FunctionDescription = {
|
|
528
|
-
description: _lt("Converts a time string into its serial number representation."),
|
|
529
|
-
args: args(`
|
|
530
|
-
time_string (string) ${_lt("The string that holds the time representation.")}
|
|
531
|
-
`),
|
|
532
|
-
returns: ["NUMBER"],
|
|
533
|
-
compute: function (time_string: any): number {
|
|
534
|
-
const _timeString = toString(time_string);
|
|
535
|
-
const datetime = parseDateTime(_timeString);
|
|
536
|
-
if (datetime === null) {
|
|
537
|
-
throw new Error(_lt("TIMEVALUE parameter '%s' cannot be parsed to date/time.", _timeString));
|
|
538
|
-
}
|
|
539
|
-
const result = datetime.value - Math.trunc(datetime.value);
|
|
540
|
-
|
|
541
|
-
return result < 0 ? 1 + result : result;
|
|
542
|
-
},
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
// -----------------------------------------------------------------------------
|
|
546
|
-
// TODAY
|
|
547
|
-
// -----------------------------------------------------------------------------
|
|
548
|
-
export const TODAY: FunctionDescription = {
|
|
549
|
-
description: _lt("Current date as a date value."),
|
|
550
|
-
args: [],
|
|
551
|
-
returns: ["DATE"],
|
|
552
|
-
compute: function (): InternalDate {
|
|
553
|
-
const today = new Date();
|
|
554
|
-
const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
555
|
-
const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
|
|
556
|
-
return {
|
|
557
|
-
value: Math.round(delta / 86400000),
|
|
558
|
-
format: "m/d/yyyy",
|
|
559
|
-
jsDate: jsDate,
|
|
560
|
-
};
|
|
561
|
-
},
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
// -----------------------------------------------------------------------------
|
|
565
|
-
// WEEKDAY
|
|
566
|
-
// -----------------------------------------------------------------------------
|
|
567
|
-
export const WEEKDAY: FunctionDescription = {
|
|
568
|
-
description: _lt("Day of the week of the date provided (as number)."),
|
|
569
|
-
args: args(`
|
|
570
|
-
date (date) ${_lt(
|
|
571
|
-
"The date for which to determine the day of the week. Must be a reference to a cell containing a date, a function returning a date type, or a number."
|
|
572
|
-
)}
|
|
573
|
-
type (number, optional, default=1) ${_lt(
|
|
574
|
-
"A number indicating which numbering system to use to represent weekdays. By default, counts starting with Sunday = 1."
|
|
575
|
-
)}
|
|
576
|
-
`),
|
|
577
|
-
returns: ["NUMBER"],
|
|
578
|
-
compute: function (date: any, type: any = 1): number {
|
|
579
|
-
const _date = toNativeDate(date);
|
|
580
|
-
const _type = Math.round(toNumber(type));
|
|
581
|
-
const m = _date.getDay();
|
|
582
|
-
switch (_type) {
|
|
583
|
-
case 1:
|
|
584
|
-
return m + 1;
|
|
585
|
-
case 2:
|
|
586
|
-
return m === 0 ? 7 : m;
|
|
587
|
-
case 3:
|
|
588
|
-
return m === 0 ? 6 : m - 1;
|
|
589
|
-
}
|
|
590
|
-
throw new Error(
|
|
591
|
-
_lt("Function WEEKDAY parameter 2 value %s is out of range.", _type.toString())
|
|
592
|
-
);
|
|
593
|
-
},
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
// -----------------------------------------------------------------------------
|
|
597
|
-
// WEEKNUM
|
|
598
|
-
// -----------------------------------------------------------------------------
|
|
599
|
-
export const WEEKNUM: FunctionDescription = {
|
|
600
|
-
description: _lt("Week number of the year."),
|
|
601
|
-
args: args(`
|
|
602
|
-
date (date) ${_lt(
|
|
603
|
-
"The date for which to determine the week number. Must be a reference to a cell containing a date, a function returning a date type, or a number."
|
|
604
|
-
)}
|
|
605
|
-
type (number, optional, default=1) ${_lt(
|
|
606
|
-
"A number representing the day that a week starts on. Sunday = 1."
|
|
607
|
-
)}
|
|
608
|
-
`),
|
|
609
|
-
returns: ["NUMBER"],
|
|
610
|
-
compute: function (date: any, type: any = 1): number {
|
|
611
|
-
const _date = toNativeDate(date);
|
|
612
|
-
const _type = Math.round(toNumber(type));
|
|
613
|
-
|
|
614
|
-
let startDayOfWeek: number;
|
|
615
|
-
|
|
616
|
-
if (_type === 1 || _type === 2) {
|
|
617
|
-
startDayOfWeek = _type - 1;
|
|
618
|
-
} else if (11 <= _type && _type <= 17) {
|
|
619
|
-
startDayOfWeek = _type - 10 === 7 ? 0 : _type - 10;
|
|
620
|
-
} else if (_type === 21) {
|
|
621
|
-
return ISOWEEKNUM.compute(date);
|
|
622
|
-
} else {
|
|
623
|
-
throw new Error(
|
|
624
|
-
_lt("Function WEEKNUM parameter 2 value %s is out of range.", _type.toString())
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
const y = _date.getFullYear();
|
|
629
|
-
|
|
630
|
-
let dayStart = 1;
|
|
631
|
-
let startDayOfFirstWeek = new Date(y, 0, dayStart);
|
|
632
|
-
|
|
633
|
-
while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
|
|
634
|
-
dayStart += 1;
|
|
635
|
-
startDayOfFirstWeek = new Date(y, 0, dayStart);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / 86400000;
|
|
639
|
-
|
|
640
|
-
if (dif < 0) {
|
|
641
|
-
return 1;
|
|
642
|
-
}
|
|
643
|
-
return Math.floor(dif / 7) + (dayStart === 1 ? 1 : 2);
|
|
644
|
-
},
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
// -----------------------------------------------------------------------------
|
|
648
|
-
// WORKDAY
|
|
649
|
-
// -----------------------------------------------------------------------------
|
|
650
|
-
export const WORKDAY: FunctionDescription = {
|
|
651
|
-
description: _lt("Number of working days from start date."),
|
|
652
|
-
args: args(`
|
|
653
|
-
start_date (date) ${_lt("The date from which to begin counting.")}
|
|
654
|
-
num_days (number) ${_lt(
|
|
655
|
-
"The number of working days to advance from start_date. If negative, counts backwards."
|
|
656
|
-
)}
|
|
657
|
-
holidays (date, range<date>, optional) ${_lt(
|
|
658
|
-
"A range or array constant containing the dates to consider holidays."
|
|
659
|
-
)}
|
|
660
|
-
`),
|
|
661
|
-
returns: ["NUMBER"],
|
|
662
|
-
compute: function (start_date: any, num_days: any, holidays: any = undefined): number {
|
|
663
|
-
return WORKDAY_INTL.compute(start_date, num_days, 1, holidays);
|
|
664
|
-
},
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
// -----------------------------------------------------------------------------
|
|
668
|
-
// WORKDAY.INTL
|
|
669
|
-
// -----------------------------------------------------------------------------
|
|
670
|
-
export const WORKDAY_INTL: FunctionDescription = {
|
|
671
|
-
description: _lt("Net working days between two dates (specifying weekends)."),
|
|
672
|
-
args: args(`
|
|
673
|
-
start_date (date) ${_lt("The date from which to begin counting.")}
|
|
674
|
-
num_days (number) ${_lt(
|
|
675
|
-
"The number of working days to advance from start_date. If negative, counts backwards."
|
|
676
|
-
)}
|
|
677
|
-
weekend (any, optional, default=1) ${_lt(
|
|
678
|
-
"A number or string representing which days of the week are considered weekends."
|
|
679
|
-
)}
|
|
680
|
-
holidays (date, range<date>, optional) ${_lt(
|
|
681
|
-
"A range or array constant containing the dates to consider holidays."
|
|
682
|
-
)}
|
|
683
|
-
`),
|
|
684
|
-
returns: ["DATE"],
|
|
685
|
-
compute: function (
|
|
686
|
-
start_date: any,
|
|
687
|
-
num_days: any,
|
|
688
|
-
weekend: any = 1,
|
|
689
|
-
holidays: any = undefined
|
|
690
|
-
): InternalDate {
|
|
691
|
-
let _startDate = toNativeDate(start_date);
|
|
692
|
-
let _numDays = Math.trunc(toNumber(num_days));
|
|
693
|
-
|
|
694
|
-
if (weekend === "1111111") {
|
|
695
|
-
throw new Error(_lt(`Function WORKDAY.INTL parameter 3 cannot be equal to '1111111'.`));
|
|
696
|
-
}
|
|
697
|
-
const daysWeekend = weekendToDayNumber(weekend);
|
|
698
|
-
|
|
699
|
-
let timesHoliday = new Set();
|
|
700
|
-
if (holidays !== undefined) {
|
|
701
|
-
visitAny(holidays, (h) => {
|
|
702
|
-
const holiday = toNativeDate(h);
|
|
703
|
-
timesHoliday.add(holiday.getTime());
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
let stepDate = new Date(_startDate.getTime());
|
|
708
|
-
let timeStepDate = stepDate.getTime();
|
|
709
|
-
|
|
710
|
-
const unitDay = Math.sign(_numDays);
|
|
711
|
-
let stepDay = Math.abs(_numDays);
|
|
712
|
-
|
|
713
|
-
while (stepDay > 0) {
|
|
714
|
-
stepDate.setDate(stepDate.getDate() + unitDay);
|
|
715
|
-
timeStepDate = stepDate.getTime();
|
|
716
|
-
|
|
717
|
-
if (!daysWeekend.includes(stepDate.getDay()) && !timesHoliday.has(timeStepDate)) {
|
|
718
|
-
stepDay -= 1;
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
const delta = timeStepDate - INITIAL_1900_DAY.getTime();
|
|
723
|
-
return {
|
|
724
|
-
value: Math.round(delta / 86400000),
|
|
725
|
-
format: "m/d/yyyy",
|
|
726
|
-
jsDate: stepDate,
|
|
727
|
-
};
|
|
728
|
-
},
|
|
729
|
-
};
|
|
730
|
-
|
|
731
|
-
// -----------------------------------------------------------------------------
|
|
732
|
-
// YEAR
|
|
733
|
-
// -----------------------------------------------------------------------------
|
|
734
|
-
export const YEAR: FunctionDescription = {
|
|
735
|
-
description: _lt("Year specified by a given date."),
|
|
736
|
-
args: args(`
|
|
737
|
-
date (date) ${_lt("The date from which to extract the year.")}
|
|
738
|
-
`),
|
|
739
|
-
returns: ["NUMBER"],
|
|
740
|
-
compute: function (date: any): number {
|
|
741
|
-
return toNativeDate(date).getFullYear();
|
|
742
|
-
},
|
|
743
|
-
};
|