@odoo/o-spreadsheet 14.0.1 → 14.0.3

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.
Files changed (204) hide show
  1. package/dist/o-spreadsheet.cjs.js +17880 -0
  2. package/dist/o-spreadsheet.d.ts +4119 -0
  3. package/dist/o-spreadsheet.esm.js +17845 -0
  4. package/dist/o-spreadsheet.iife.js +17882 -0
  5. package/dist/o-spreadsheet.iife.min.js +1446 -0
  6. package/package.json +32 -9
  7. package/readme.md +10 -0
  8. package/.eslintrc.json +0 -20
  9. package/.husky/post-checkout +0 -9
  10. package/.husky/pre-commit +0 -39
  11. package/.prettierignore +0 -1
  12. package/astToFormula.patch +0 -0
  13. package/demo/data.js +0 -255
  14. package/demo/index.html +0 -9
  15. package/demo/libs/Chart.bundle.js +0 -20755
  16. package/demo/main.js +0 -101
  17. package/doc/readme.md +0 -46
  18. package/rollup.config.js +0 -23
  19. package/src/base_plugin.ts +0 -102
  20. package/src/components/autofill.ts +0 -146
  21. package/src/components/bottom_bar.ts +0 -199
  22. package/src/components/color_picker.ts +0 -150
  23. package/src/components/composer/autocomplete_dropdown.ts +0 -135
  24. package/src/components/composer/composer.ts +0 -487
  25. package/src/components/composer/content_editable_helper.ts +0 -146
  26. package/src/components/figures/chart.ts +0 -70
  27. package/src/components/figures/container.ts +0 -268
  28. package/src/components/figures/text_figure.ts +0 -36
  29. package/src/components/grid.ts +0 -635
  30. package/src/components/helpers/dom_helpers.ts +0 -7
  31. package/src/components/helpers/drag_and_drop.ts +0 -17
  32. package/src/components/icons.ts +0 -36
  33. package/src/components/index.ts +0 -1
  34. package/src/components/menu.ts +0 -288
  35. package/src/components/overlay.ts +0 -457
  36. package/src/components/scrollbar.ts +0 -22
  37. package/src/components/selection_input.ts +0 -168
  38. package/src/components/side_panel/cell_is_rule_editor.ts +0 -169
  39. package/src/components/side_panel/chart_panel.ts +0 -104
  40. package/src/components/side_panel/color_scale_rule_editor.ts +0 -145
  41. package/src/components/side_panel/conditional_formatting.ts +0 -396
  42. package/src/components/side_panel/side_panel.ts +0 -127
  43. package/src/components/side_panel/translations_terms.ts +0 -45
  44. package/src/components/spreadsheet.ts +0 -198
  45. package/src/components/top_bar.ts +0 -535
  46. package/src/constants.ts +0 -26
  47. package/src/data.ts +0 -149
  48. package/src/fonts.ts +0 -41
  49. package/src/formulas/compiler.ts +0 -258
  50. package/src/formulas/composer_tokenizer.ts +0 -70
  51. package/src/formulas/index.ts +0 -15
  52. package/src/formulas/normalize.ts +0 -52
  53. package/src/formulas/parser.ts +0 -280
  54. package/src/formulas/range_tokenizer.ts +0 -97
  55. package/src/formulas/tokenizer.ts +0 -242
  56. package/src/functions/arguments.ts +0 -114
  57. package/src/functions/dates.ts +0 -302
  58. package/src/functions/helpers.ts +0 -592
  59. package/src/functions/index.ts +0 -52
  60. package/src/functions/module_database.ts +0 -282
  61. package/src/functions/module_date.ts +0 -743
  62. package/src/functions/module_info.ts +0 -69
  63. package/src/functions/module_logical.ts +0 -208
  64. package/src/functions/module_lookup.ts +0 -185
  65. package/src/functions/module_math.ts +0 -1252
  66. package/src/functions/module_operators.ts +0 -291
  67. package/src/functions/module_statistical.ts +0 -882
  68. package/src/functions/module_text.ts +0 -370
  69. package/src/helpers/color.ts +0 -30
  70. package/src/helpers/coordinates.ts +0 -71
  71. package/src/helpers/grid_manipulation.ts +0 -68
  72. package/src/helpers/index.ts +0 -7
  73. package/src/helpers/misc.ts +0 -76
  74. package/src/helpers/numbers.ts +0 -117
  75. package/src/helpers/uuid.ts +0 -19
  76. package/src/helpers/zones.ts +0 -263
  77. package/src/history.ts +0 -186
  78. package/src/index.ts +0 -84
  79. package/src/model.ts +0 -261
  80. package/src/plugins/autofill.ts +0 -412
  81. package/src/plugins/chart.ts +0 -404
  82. package/src/plugins/clipboard.ts +0 -461
  83. package/src/plugins/conditional_format.ts +0 -445
  84. package/src/plugins/core.ts +0 -1502
  85. package/src/plugins/edition.ts +0 -157
  86. package/src/plugins/evaluation.ts +0 -428
  87. package/src/plugins/figures.ts +0 -123
  88. package/src/plugins/formatting.ts +0 -630
  89. package/src/plugins/highlight.ts +0 -187
  90. package/src/plugins/index.ts +0 -32
  91. package/src/plugins/merge.ts +0 -524
  92. package/src/plugins/renderer.ts +0 -571
  93. package/src/plugins/selection.ts +0 -562
  94. package/src/plugins/selection_inputs.ts +0 -326
  95. package/src/registries/autofill_modifiers.ts +0 -76
  96. package/src/registries/autofill_rules.ts +0 -98
  97. package/src/registries/figure_registry.ts +0 -30
  98. package/src/registries/index.ts +0 -7
  99. package/src/registries/menu_items_registry.ts +0 -110
  100. package/src/registries/menus/cell_menu_registry.ts +0 -79
  101. package/src/registries/menus/col_menu_registry.ts +0 -63
  102. package/src/registries/menus/index.ts +0 -6
  103. package/src/registries/menus/menu_items_actions.ts +0 -425
  104. package/src/registries/menus/row_menu_registry.ts +0 -63
  105. package/src/registries/menus/sheet_menu_registry.ts +0 -75
  106. package/src/registries/menus/topbar_menu_registry.ts +0 -204
  107. package/src/registries/side_panel_registry.ts +0 -26
  108. package/src/registries/topbar_component_registry.ts +0 -12
  109. package/src/registry.ts +0 -51
  110. package/src/translation.ts +0 -44
  111. package/src/types/autofill.ts +0 -48
  112. package/src/types/chart.ts +0 -26
  113. package/src/types/commands.ts +0 -716
  114. package/src/types/conditional_formatting.ts +0 -124
  115. package/src/types/env.ts +0 -13
  116. package/src/types/functions.ts +0 -35
  117. package/src/types/getters.ts +0 -103
  118. package/src/types/index.ts +0 -20
  119. package/src/types/misc.ts +0 -143
  120. package/src/types/rendering.ts +0 -41
  121. package/src/types/workbook_data.ts +0 -62
  122. package/tests/__mocks__/uuid.ts +0 -7
  123. package/tests/canvas.mock.ts +0 -34
  124. package/tests/components/__mocks__/content_editable_helper.ts +0 -79
  125. package/tests/components/__mocks__/scrollbar.ts +0 -18
  126. package/tests/components/__snapshots__/autocomplete_dropdown_test.ts.snap +0 -29
  127. package/tests/components/__snapshots__/bottom_bar_test.ts.snap +0 -75
  128. package/tests/components/__snapshots__/context_menu_test.ts.snap +0 -88
  129. package/tests/components/__snapshots__/grid_test.ts.snap +0 -60
  130. package/tests/components/__snapshots__/spreadsheet_test.ts.snap +0 -455
  131. package/tests/components/__snapshots__/top_bar_test.ts.snap +0 -705
  132. package/tests/components/autocomplete_dropdown_test.ts +0 -315
  133. package/tests/components/autofill_test.ts +0 -167
  134. package/tests/components/bottom_bar_test.ts +0 -262
  135. package/tests/components/chart_side_panel_test.ts +0 -123
  136. package/tests/components/composer_test.ts +0 -400
  137. package/tests/components/context_menu_test.ts +0 -825
  138. package/tests/components/grid_manipulation_test.ts +0 -163
  139. package/tests/components/grid_test.ts +0 -581
  140. package/tests/components/overlay_test.ts +0 -541
  141. package/tests/components/selection_input_test.ts +0 -259
  142. package/tests/components/side_panel_test.ts +0 -148
  143. package/tests/components/spreadsheet_test.ts +0 -194
  144. package/tests/components/top_bar_test.ts +0 -427
  145. package/tests/data_test.ts +0 -175
  146. package/tests/dom_helper.ts +0 -42
  147. package/tests/formulas/__snapshots__/compiler_test.ts.snap +0 -302
  148. package/tests/formulas/compiler_test.ts +0 -266
  149. package/tests/formulas/composer_tokenizer_test.ts +0 -137
  150. package/tests/formulas/expressions_test.ts +0 -57
  151. package/tests/formulas/formulas_test.ts +0 -80
  152. package/tests/formulas/normalize_test.ts +0 -82
  153. package/tests/formulas/parser_test.ts +0 -224
  154. package/tests/formulas/range_tokenizer_test.ts +0 -187
  155. package/tests/formulas/tokenizer_test.ts +0 -164
  156. package/tests/functions/arguments_test.ts +0 -141
  157. package/tests/functions/dates_test.ts +0 -1081
  158. package/tests/functions/functions_test.ts +0 -53
  159. package/tests/functions/helper_test.ts +0 -98
  160. package/tests/functions/module_database_test.ts +0 -311
  161. package/tests/functions/module_date_test.ts +0 -941
  162. package/tests/functions/module_info_test.ts +0 -139
  163. package/tests/functions/module_logical_test.ts +0 -369
  164. package/tests/functions/module_lookup_test.ts +0 -541
  165. package/tests/functions/module_math_test.ts +0 -2482
  166. package/tests/functions/module_operators_test.ts +0 -955
  167. package/tests/functions/module_statistical_test.ts +0 -2014
  168. package/tests/functions/module_text_test.ts +0 -667
  169. package/tests/helpers/coordinates_test.ts +0 -25
  170. package/tests/helpers/misc_test.ts +0 -95
  171. package/tests/helpers/numbers_test.ts +0 -196
  172. package/tests/helpers/zones_test.ts +0 -97
  173. package/tests/helpers.ts +0 -384
  174. package/tests/menu_items_registry_test.ts +0 -540
  175. package/tests/model/plugins/__snapshots__/chart_test.ts.snap +0 -90
  176. package/tests/model/plugins/chart_test.ts +0 -562
  177. package/tests/model_test.ts +0 -82
  178. package/tests/plugins/__snapshots__/conditional_formatting_test.ts.snap +0 -131
  179. package/tests/plugins/__snapshots__/renderer_test.ts.snap +0 -371
  180. package/tests/plugins/autofill_test.ts +0 -457
  181. package/tests/plugins/borders_test.ts +0 -295
  182. package/tests/plugins/clipboard_test.ts +0 -1180
  183. package/tests/plugins/conditional_formatting_test.ts +0 -1253
  184. package/tests/plugins/core_test.ts +0 -614
  185. package/tests/plugins/edition_test.ts +0 -100
  186. package/tests/plugins/evaluation_async_test.ts +0 -332
  187. package/tests/plugins/evaluation_dates_test.ts +0 -79
  188. package/tests/plugins/evaluation_test.ts +0 -901
  189. package/tests/plugins/figures_test.ts +0 -327
  190. package/tests/plugins/formatting_test.ts +0 -391
  191. package/tests/plugins/grid_manipulation_test.ts +0 -1366
  192. package/tests/plugins/highlight_test.ts +0 -413
  193. package/tests/plugins/history_test.ts +0 -142
  194. package/tests/plugins/import_export_test.ts +0 -276
  195. package/tests/plugins/merges_test.ts +0 -490
  196. package/tests/plugins/navigation_test.ts +0 -181
  197. package/tests/plugins/plugins/evaluation_test.ts +0 -111
  198. package/tests/plugins/renderer_test.ts +0 -598
  199. package/tests/plugins/resizing_test.ts +0 -152
  200. package/tests/plugins/selection_input_test.ts +0 -409
  201. package/tests/plugins/selection_test.ts +0 -442
  202. package/tests/plugins/sheets_test.ts +0 -643
  203. package/tests/plugins/style_test.ts +0 -90
  204. 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
- };