commit
message
Fixing up some of the delimiter issues.
author
Ben Vogt <[email protected]>
date
2017-04-01 22:00:31
stats
3 file(s) changed,
147 insertions(+),
93 deletions(-)
files
src/RawFormulas/Date.ts
src/RawFormulas/Utils.ts
tests/DateFormulasTest.ts
1diff --git a/src/RawFormulas/Date.ts b/src/RawFormulas/Date.ts
2index ec345b1..362b159 100644
3--- a/src/RawFormulas/Date.ts
4+++ b/src/RawFormulas/Date.ts
5@@ -45,17 +45,22 @@ var DATE = function (...values) {
6
7 const YEAR_MONTHDIG_DAY = DateRegExBuilder.DateRegExBuilder()
8 .start()
9- .OPTIONAL_DAYNAME().OPTIONAL_COMMA().YYYY().FLEX_DELIMITER().MM().FLEX_DELIMITER().DD_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
10+ .OPTIONAL_DAYNAME().OPTIONAL_COMMA().YYYY().FLEX_DELIMITER_LOOSEDOT().MM().FLEX_DELIMITER_LOOSEDOT().DD_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
11 .end()
12 .build();
13 const MONTHDIG_DAY_YEAR = DateRegExBuilder.DateRegExBuilder()
14 .start()
15- .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MM().FLEX_DELIMITER().DD().FLEX_DELIMITER().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
16+ .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MM().FLEX_DELIMITER_LOOSEDOT().DD().FLEX_DELIMITER_LOOSEDOT().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
17 .end()
18 .build();
19 const DAY_MONTHNAME_YEAR = DateRegExBuilder.DateRegExBuilder()
20 .start()
21- .OPTIONAL_DAYNAME().OPTIONAL_COMMA().DD().FLEX_DELIMITER().MONTHNAME().FLEX_DELIMITER().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
22+ .OPTIONAL_DAYNAME().OPTIONAL_COMMA().DD().FLEX_DELIMITER_LOOSEDOT().MONTHNAME().FLEX_DELIMITER_LOOSEDOT().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
23+ .end()
24+ .build();
25+const MONTHNAME_DAY_YEAR = DateRegExBuilder.DateRegExBuilder()
26+ .start()
27+ .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MONTHNAME().FLEX_DELIMITER_LOOSEDOT().DD().FLEX_DELIMITER_LOOSEDOT().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
28 .end()
29 .build();
30 const YEAR_MONTHDIG = DateRegExBuilder.DateRegExBuilder()
31@@ -75,7 +80,7 @@ const YEAR_MONTHNAME = DateRegExBuilder.DateRegExBuilder()
32 .build();
33 const MONTHNAME_YEAR = DateRegExBuilder.DateRegExBuilder()
34 .start()
35- .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MONTHNAME().FLEX_DELIMITER().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
36+ .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MONTHNAME().FLEX_DELIMITER().YYYY2_OR_4_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
37 .end()
38 .build();
39 // For reference: https://regex101.com/r/47GARA/1/
40@@ -85,7 +90,6 @@ const TIMESTAMP = DateRegExBuilder.DateRegExBuilder()
41 .end()
42 .build();
43
44-
45 /**
46 * Converts a provided date string in a known format to a date value.
47 * @param values[0] date_string - The string representing the date. Understood formats include any date format which is
48@@ -129,14 +133,13 @@ var DATEVALUE = function (...values) : number {
49 }
50
51 /**
52- *
53- * @param timestampString
54- * @param momentToMutate
55- * @returns {moment.Moment}
56+ * Matches a timestamp string, adding the units to the moment passed in.
57+ * @param timestampString to parse. ok formats: "10am", "10:10", "10:10am", "10:10:10", "10:10:10am", etc.
58+ * @param momentToMutate to mutate
59+ * @returns {Moment} mutated and altered.
60 */
61 function matchTimestampAndMutateMoment(timestampString : string, momentToMutate: moment.Moment) : moment.Moment {
62 var matches = timestampString.match(TIMESTAMP);
63- // console.log("match and mutating:", timestampString, "from", dateString, matches);
64 if (matches && matches[1] !== undefined) { // 10am
65 var hours = parseInt(matches[2]);
66 if (hours > 12) {
67@@ -274,6 +277,25 @@ var DATEVALUE = function (...values) : number {
68 }
69 }
70
71+ // Check MONTHNAME_DAY_YEAR, Month(fd)DD(fd)YYYY, 'Aug 19 2020'
72+ if (m === undefined) {
73+ var matches = dateString.match(MONTHNAME_DAY_YEAR);
74+ if (matches && matches.length >= 8) {
75+ // Check delimiters. If they're not the same, throw error.
76+ if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
77+ throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
78+ }
79+ var years = parseInt(matches[7]);
80+ var monthName = matches[3];
81+ var days = parseInt(matches[5]) - 1; // Days are zero indexed.
82+ var tmpMoment = createMoment(years, monthName, days);
83+ if (matches.length >= 9 && matches[8] !== undefined) {
84+ tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
85+ }
86+ m = tmpMoment;
87+ }
88+ }
89+
90 // Check DAY_MONTHNAME_YEAR, DD(fd)Month(fd)YYYY, '24/July/1992'
91 if (m === undefined) {
92 var matches = dateString.match(DAY_MONTHNAME_YEAR);
93diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
94index 6b3e591..767b26f 100644
95--- a/src/RawFormulas/Utils.ts
96+++ b/src/RawFormulas/Utils.ts
97@@ -505,13 +505,31 @@ class DateRegExBuilder {
98 return this;
99 }
100
101+ YYYY2_OR_4_W_SPACE() : DateRegExBuilder {
102+ this.regexString += "([0-9]{2}|[0-9]{4}|[0-9]{2}\\s+|[0-9]{4}\\s+)";
103+ return this;
104+ }
105+
106 /**
107- * Add capture group for a flexible delimiter, including ", ", " ", ".", "\", "-".
108+ * Add capture group for a flexible delimiter, including ", ", " ", ". ", "\", "-".
109 * @returns {DateRegExBuilder} builder
110 * @constructor
111 */
112 FLEX_DELIMITER() : DateRegExBuilder {
113- this.regexString += "(,?\\s+|\\s*-?\\.?-?\\/?\\s*)";
114+ // this.regexString += "(,?\\s+|\\s*-?\\.?-?\\/?\\s+)";// close to being right
115+ this.regexString += "(,?\\s+|\\s*\\.\\s+|\\s*-\\s*|\\s*\\/\\s*)";
116+ return this;
117+ }
118+
119+ /**
120+ * Add capture group for a flexible delimiter, including ", ", " ", ".", "\", "-". Different from FLEX_DELIMITER
121+ * in that it will match periods with zero or more spaces on either side.
122+ * @returns {DateRegExBuilder} builder
123+ * @constructor
124+ */
125+ FLEX_DELIMITER_LOOSEDOT() : DateRegExBuilder {
126+ // this.regexString += "(,?\\s+|\\s*-?\\.?-?\\/?\\s+)";// close to being right
127+ this.regexString += "(,?\\s+|\\s*\\.\\s*|\\s*-\\s*|\\s*\\/\\s*)";
128 return this;
129 }
130
131diff --git a/tests/DateFormulasTest.ts b/tests/DateFormulasTest.ts
132index acc7346..bdaf288 100644
133--- a/tests/DateFormulasTest.ts
134+++ b/tests/DateFormulasTest.ts
135@@ -423,6 +423,13 @@ assertEquals(DATEVALUE("20 Sep 2015"), 42267);
136 assertEquals(DATEVALUE("20 Oct 2015"), 42297);
137 assertEquals(DATEVALUE("20 Nov 2015"), 42328);
138 assertEquals(DATEVALUE("20 Dec 2015"), 42358);
139+assertEquals(DATEVALUE("29 Feb 2004"), 38046); // leap year, 29th ok
140+catchAndAssertEquals(function() {
141+ DATEVALUE("29 Feb 2001");// not leap year, 29th not ok
142+}, ERRORS.VALUE_ERROR);
143+catchAndAssertEquals(function() {
144+ DATEVALUE("32 June 2001");// overload numbers not ok
145+}, ERRORS.VALUE_ERROR);
146 // delimiter tests
147 assertEquals(DATEVALUE("Sun, 09, Feb, 2017"), 42775);
148 assertEquals(DATEVALUE("Sun, 09/Feb/2017"), 42775);
149@@ -440,7 +447,7 @@ catchAndAssertEquals(function() {
150 DATEVALUE("09,Feb,2017");
151 }, ERRORS.VALUE_ERROR);
152 // timestamp tests
153-assertEquals(DATEVALUE("24/June/1992 10am"), 33779); // TODO: come back to these. right now just testing to make sure they don't break anything.
154+assertEquals(DATEVALUE("24/June/1992 10am"), 33779);
155 assertEquals(DATEVALUE("24/June/1992 10:10"), 33779);
156 assertEquals(DATEVALUE("24/June/1992 10:10am"), 33779);
157 assertEquals(DATEVALUE("24/June/1992 10:10:10"), 33779);
158@@ -450,6 +457,27 @@ assertEquals(DATEVALUE("24/June/1992 10: 10 "), 33779);
159 assertEquals(DATEVALUE("24/June/1992 10: 10 pm"), 33779);
160 assertEquals(DATEVALUE("24/June/1992 10: 10: 10"), 33779);
161 assertEquals(DATEVALUE("24/June/1992 10: 10: 10 am "), 33779);
162+// MONTHNAME_DAY_YEAR, Month(fd)DD(fd)YYYY, 'Aug 19 2020' =============================================================================
163+assertEquals(DATEVALUE("Sun Feb 09 2017"), 42775);
164+assertEquals(DATEVALUE("Sun Feb 9 2017"), 42775);
165+assertEquals(DATEVALUE("Mon Feb 09 2017"), 42775);
166+assertEquals(DATEVALUE("Thursday Feb 09 2017"), 42775);
167+assertEquals(DATEVALUE("Thursday February 09 2017"), 42775);
168+assertEquals(DATEVALUE("Sun September 01 20"), 44075);
169+assertEquals(DATEVALUE("Sun, Feb, 09, 2017"), 42775);
170+assertEquals(DATEVALUE("May 20 1992"), 33744);
171+assertEquals(DATEVALUE("December 31 100"), -657070);
172+assertEquals(DATEVALUE("January 13 0030"), 10971);
173+assertEquals(DATEVALUE("January 13 1200"), -255656);
174+assertEquals(DATEVALUE("January 22 2222"), 117631);
175+assertEquals(DATEVALUE("November 3 4243"), 856071);
176+assertEquals(DATEVALUE("Feb 29 2004"), 38046); // leap year, 29th ok
177+catchAndAssertEquals(function() {
178+ DATEVALUE("Feb 29 2001");// not leap year, 29th not ok
179+}, ERRORS.VALUE_ERROR);
180+catchAndAssertEquals(function() {
181+ DATEVALUE("June 32 2001");// overload numbers not ok
182+}, ERRORS.VALUE_ERROR);
183 // YEAR_MONTHDIG, YYYY(fd)MM, '1992/06' ================================================================================
184 assertEquals(DATEVALUE("2017/01"), 42736);
185 assertEquals(DATEVALUE("2017/02"), 42767);
186@@ -469,12 +497,16 @@ assertEquals(DATEVALUE("Thursday 2017/01"), 42736);
187 assertEquals(DATEVALUE("Thursday, 2017/01"), 42736);
188 assertEquals(DATEVALUE("2017/01"), 42736);
189 assertEquals(DATEVALUE("2017-01"), 42736);
190-assertEquals(DATEVALUE("2017.01"), 42736);
191+assertEquals(DATEVALUE("2017. 01"), 42736);
192+assertEquals(DATEVALUE("2017 01"), 42736);
193 assertEquals(DATEVALUE("2017, 01"), 42736);
194-// Comma delimiters should be followed by spaces.
195+// Comma and period delimiters should be followed by spaces.
196 catchAndAssertEquals(function() {
197 DATEVALUE("2017,01");
198 }, ERRORS.VALUE_ERROR);
199+catchAndAssertEquals(function() {
200+ DATEVALUE("2017.01");
201+}, ERRORS.VALUE_ERROR);
202 // timestamp test
203 assertEquals(DATEVALUE("2017-01 10am"), 42736); // TODO: come back to these. right now just testing to make sure they don't break anything.
204 assertEquals(DATEVALUE("2017-01 10:10"), 42736);
205@@ -504,12 +536,15 @@ assertEquals(DATEVALUE("Thursday 01/2017"), 42736);
206 assertEquals(DATEVALUE("Thursday, 01/2017"), 42736);
207 assertEquals(DATEVALUE("1/2017"), 42736);
208 assertEquals(DATEVALUE("01-2017"), 42736);
209-assertEquals(DATEVALUE("01.2017"), 42736);
210+assertEquals(DATEVALUE("01. 2017"), 42736);
211 assertEquals(DATEVALUE("01, 2017"), 42736);
212-// Comma delimiters should be followed by spaces.
213+// Comma, period delimiters should be followed by spaces.
214 catchAndAssertEquals(function() {
215 DATEVALUE("01,2017");
216 }, ERRORS.VALUE_ERROR);
217+catchAndAssertEquals(function() {
218+ DATEVALUE("01.2017");
219+}, ERRORS.VALUE_ERROR);
220 // 0 is not a month
221 catchAndAssertEquals(function() {
222 DATEVALUE("0/2017");
223@@ -543,12 +578,15 @@ assertEquals(DATEVALUE("Thursday 2017 January"), 42736);
224 assertEquals(DATEVALUE("Thursday, 2017 January"), 42736);
225 assertEquals(DATEVALUE("2017/January"), 42736);
226 assertEquals(DATEVALUE("2017-January"), 42736);
227-assertEquals(DATEVALUE("2017.January"), 42736);
228+assertEquals(DATEVALUE("2017. January"), 42736);
229 assertEquals(DATEVALUE("2017, January"), 42736);
230 // Comma delimiters should be followed by spaces.
231 catchAndAssertEquals(function() {
232 DATEVALUE("2017,January");
233 }, ERRORS.VALUE_ERROR);
234+catchAndAssertEquals(function() {
235+ DATEVALUE("2017.January");
236+}, ERRORS.VALUE_ERROR);
237 // timestamp test
238 assertEquals(DATEVALUE("2017-January 10am"), 42736); // TODO: come back to these. right now just testing to make sure they don't break anything.
239 assertEquals(DATEVALUE("2017-January 10:10"), 42736);
240@@ -575,24 +613,46 @@ assertEquals(DATEVALUE("November 2017"), 43040);
241 assertEquals(DATEVALUE("December 2017"), 43070);
242 assertEquals(DATEVALUE(" Feb 2017 "), 42767);
243 assertEquals(DATEVALUE("Feb-2017"), 42767);
244-assertEquals(DATEVALUE("Feb.2017"), 42767);
245+assertEquals(DATEVALUE("Feb. 2017"), 42767);
246 assertEquals(DATEVALUE("Feb/2017"), 42767);
247 assertEquals(DATEVALUE("Feb . 2017"), 42767);
248 assertEquals(DATEVALUE("Feb - 2017"), 42767);
249 assertEquals(DATEVALUE("January 0030"), 10959);
250 assertEquals(DATEVALUE("November 4243"), 856069);
251 assertEquals(DATEVALUE("December 0100"), -657100);
252+assertEquals(DATEVALUE("Jan 2017"), 42736);
253+assertEquals(DATEVALUE("Feb 2017"), 42767);
254+assertEquals(DATEVALUE("Mar 2017"), 42795);
255+assertEquals(DATEVALUE("Apr 2017"), 42826);
256+assertEquals(DATEVALUE("May 2017"), 42856);
257+assertEquals(DATEVALUE("Jun 2017"), 42887);
258+assertEquals(DATEVALUE("Jul 2017"), 42917);
259+assertEquals(DATEVALUE("Aug 2017"), 42948);
260+assertEquals(DATEVALUE("Sep 2017"), 42979);
261+assertEquals(DATEVALUE("Oct 2017"), 43009);
262+assertEquals(DATEVALUE("Nov 2017"), 43040);
263+assertEquals(DATEVALUE("Dec 2017"), 43070);
264+assertEquals(DATEVALUE("Feb, 2017"), 42767);
265+catchAndAssertEquals(function() {
266+ DATEVALUE("December 100");// need 4 digits
267+}, ERRORS.VALUE_ERROR);
268+catchAndAssertEquals(function() {
269+ DATEVALUE("Dec.20");// need space after if using period
270+}, ERRORS.VALUE_ERROR);
271 // delimiter tests
272 assertEquals(DATEVALUE("Thursday January 2017"), 42736);
273 assertEquals(DATEVALUE("Thursday, January 2017"), 42736);
274 assertEquals(DATEVALUE("January/2017"), 42736);
275 assertEquals(DATEVALUE("January-2017"), 42736);
276-assertEquals(DATEVALUE("January.2017"), 42736);
277+assertEquals(DATEVALUE("January. 2017"), 42736);
278 assertEquals(DATEVALUE("January, 2017"), 42736);
279-// Comma delimiters should be followed by spaces.
280+// Comma, period delimiters should be followed by spaces.
281 catchAndAssertEquals(function() {
282 DATEVALUE("January,2017");
283 }, ERRORS.VALUE_ERROR);
284+catchAndAssertEquals(function() {
285+ DATEVALUE("January.2017");
286+}, ERRORS.VALUE_ERROR);
287 // timestamp test
288 assertEquals(DATEVALUE("January-2017 10am"), 42736); // TODO: come back to these. right now just testing to make sure they don't break anything.
289 assertEquals(DATEVALUE("January-2017 10:10"), 42736);
290@@ -604,67 +664,3 @@ assertEquals(DATEVALUE("January-2017 10: 10 "), 42736);
291 assertEquals(DATEVALUE("January-2017 10: 10 pm"), 42736);
292 assertEquals(DATEVALUE("January-2017 10: 10: 10"), 42736);
293 assertEquals(DATEVALUE("January-2017 10: 10: 10 am "), 42736);
294-
295-
296-
297-
298-
299-
300-
301-
302-
303-
304-
305-
306-
307-
308-// assertEquals(DATEVALUE("Sun Feb 09 2017"), 42775);
309-// assertEquals(DATEVALUE("Sun Feb 9 2017"), 42775);
310-// assertEquals(DATEVALUE("Mon Feb 09 2017"), 42775);
311-// assertEquals(DATEVALUE("Thursday Feb 09 2017"), 42775);
312-// assertEquals(DATEVALUE("Thursday February 09 2017"), 42775);
313-// assertEquals(DATEVALUE("Sun September 01 20"), 44075);
314-// assertEquals(DATEVALUE("Sun, Feb, 09, 2017"), 42775);
315-// assertEquals(DATEVALUE("May 20 1992"), 33744);
316-// assertEquals(DATEVALUE("December 31 100"), -657070);
317-// assertEquals(DATEVALUE("January 13 0030"), 10971);
318-// assertEquals(DATEVALUE("January 13 1200"), -255656);
319-// assertEquals(DATEVALUE("January 22 2222"), 117631);
320-// assertEquals(DATEVALUE("November 3 4243"), 856071);
321-// assertEquals(DATEVALUE("Feb 29 2004"), 38046); // leap year, 29th ok
322-// catchAndAssertEquals(function() {
323-// DATEVALUE("Feb 29 2001");// not leap year, 29th not ok
324-// }, ERRORS.VALUE_ERROR);
325-// catchAndAssertEquals(function() {
326-// DATEVALUE("June 32 2001");// overload numbers not ok
327-// }, ERRORS.VALUE_ERROR);
328-// // (Dayname) DD Month YYYY
329-// assertEquals(DATEVALUE("29 Feb 2004"), 38046); // leap year, 29th ok
330-// catchAndAssertEquals(function() {
331-// DATEVALUE("29 Feb 2001");// not leap year, 29th not ok
332-// }, ERRORS.VALUE_ERROR);
333-// catchAndAssertEquals(function() {
334-// DATEVALUE("32 June 2001");// overload numbers not ok
335-// }, ERRORS.VALUE_ERROR);
336-
337-
338-// assertEquals(DATEVALUE("Jan 2017"), 42736);
339-// assertEquals(DATEVALUE("Feb 2017"), 42767);
340-// assertEquals(DATEVALUE("Mar 2017"), 42795);
341-// assertEquals(DATEVALUE("Apr 2017"), 42826);
342-// assertEquals(DATEVALUE("May 2017"), 42856);
343-// assertEquals(DATEVALUE("Jun 2017"), 42887);
344-// assertEquals(DATEVALUE("Jul 2017"), 42917);
345-// assertEquals(DATEVALUE("Aug 2017"), 42948);
346-// assertEquals(DATEVALUE("Sep 2017"), 42979);
347-// assertEquals(DATEVALUE("Oct 2017"), 43009);
348-// assertEquals(DATEVALUE("Nov 2017"), 43040);
349-// assertEquals(DATEVALUE("Dec 2017"), 43070);
350-// assertEquals(DATEVALUE("Feb, 2017"), 42767);
351-// catchAndAssertEquals(function() {
352-// DATEVALUE("December 100");// need 4 digits
353-// }, ERRORS.VALUE_ERROR);
354-// catchAndAssertEquals(function() {
355-// DATEVALUE("Dec.20");// need space if using period
356-// }, ERRORS.VALUE_ERROR);
357-//