spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
Timestamp regex functioning, still filling out tests
author
Ben Vogt <[email protected]>
date
2017-04-01 20:54:45
stats
3 file(s) changed, 203 insertions(+), 219 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 53b61ae..b6cd9f2 100644
  3--- a/src/RawFormulas/Date.ts
  4+++ b/src/RawFormulas/Date.ts
  5@@ -136,43 +136,59 @@ var DATEVALUE = function (...values) : number {
  6    */
  7   function matchTimestampAndMutateMoment(timestampString : string, momentToMutate: moment.Moment) : moment.Moment {
  8     var matches = timestampString.match(TIMESTAMP);
  9+    // console.log("match and mutating:", timestampString, "from", dateString, matches);
 10     if (matches && matches[1] !== undefined) { // 10am
 11       var hours = parseInt(matches[2]);
 12-      var amTrue = (matches[5].toLowerCase() === "am");
 13       if (hours > 12) {
 14         throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 15       }
 16       // No op on momentToMutate because you can't overload hours with am/pm.
 17-    } if (matches && matches[6] !== undefined) { // 10:10
 18+    } else if (matches && matches[6] !== undefined) { // 10:10
 19       var hours = parseInt(matches[7]);
 20       var minutes = parseInt(matches[8]);
 21       momentToMutate.add(hours, 'hours').add(minutes, 'minutes');
 22-    } if (matches && matches[11] !== undefined) { // 10:10am
 23+    } else if (matches && matches[11] !== undefined) { // 10:10am
 24       var hours = parseInt(matches[13]);
 25       var minutes = parseInt(matches[14]);
 26-      var amTrue = (matches[16].toLowerCase() === "am");
 27+      var pmTrue = (matches[16].toLowerCase() === "pm");
 28       if (hours > 12) {
 29         throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 30       }
 31-      momentToMutate.add(hours, 'hours').add(minutes, 'minutes'); // TODO: don't I add or remove 12 hours?
 32-    } if (matches && matches[17] !== undefined) { // 10:10:10
 33+      if (pmTrue) {
 34+        // 12pm is just 0am, 4pm is 16, etc.
 35+        momentToMutate.set('hours', hours === 12 ? hours : 12 + hours);
 36+      } else {
 37+        if (hours !== 12) {
 38+          momentToMutate.set('hours', hours);
 39+        }
 40+      }
 41+      momentToMutate.add(minutes, 'minutes');
 42+    } else if (matches && matches[17] !== undefined) { // 10:10:10
 43       var hours = parseInt(matches[19]);
 44       var minutes = parseInt(matches[20]);
 45       var seconds = parseInt(matches[21]);
 46       momentToMutate.add(hours, 'hours').add(minutes, 'minutes').add(seconds, 'seconds');
 47-    } if (matches && matches[23] !== undefined) { // // 10:10:10am
 48+    } else if (matches && matches[23] !== undefined) { // // 10:10:10am
 49       var hours = parseInt(matches[25]);
 50       var minutes = parseInt(matches[26]);
 51       var seconds = parseInt(matches[27]);
 52-      var amTrue = (matches[28].toLowerCase() === "am");
 53+      var pmTrue = (matches[28].toLowerCase() === "pm");
 54       if (hours > 12) {
 55         throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 56       }
 57-      momentToMutate.add(hours, 'hours').add(minutes, 'minutes').add(seconds, 'seconds');
 58+      if (pmTrue) {
 59+        // 12pm is just 0am, 4pm is 16, etc.
 60+        momentToMutate.set('hours', hours === 12 ? hours : 12 + hours);
 61+      } else {
 62+        if (hours !== 12) {
 63+          momentToMutate.set('hours', hours);
 64+        }
 65+      }
 66+      momentToMutate.add(minutes, 'minutes').add(seconds, 'seconds');
 67     } else {
 68-      // TODO: Throw error if no match found by now.
 69+      throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 70     }
 71-    return momentToMutate;
 72+    return momentToMutate.set('hours', 0).set('minutes', 0);
 73   }
 74 
 75   // Check YEAR_MONTHDIG, YYYY(fd)MM, '1992/06'
 76@@ -184,7 +200,6 @@ var DATEVALUE = function (...values) : number {
 77       var months = parseInt(matches[5]) - 1; // Months are zero indexed.
 78       var tmpMoment = createMoment(years, months, 0);
 79       if (matches[6] !== undefined) {
 80-        console.log("YEAR_MONTHDIG matched timestamp", matches[6]);
 81         tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
 82       }
 83       m = tmpMoment;
 84@@ -195,9 +210,6 @@ var DATEVALUE = function (...values) : number {
 85   if (m === undefined) {
 86     var matches = dateString.match(YEAR_MONTHDIG_DAY);
 87     if (matches && matches.length >= 8) {
 88-      if (matches.length >= 9 && matches[8] !== undefined) {
 89-        console.log("YEAR_MONTHDIG_DAY matched timestamp", matches[8]);
 90-      }
 91       // Check delimiters. If they're not the same, throw error.
 92       if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
 93         throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 94@@ -205,7 +217,11 @@ var DATEVALUE = function (...values) : number {
 95       var years = parseInt(matches[3]);
 96       var months = parseInt(matches[5]) - 1; // Months are zero indexed.
 97       var days = parseInt(matches[7]) - 1; // Days are zero indexed.
 98-      m = createMoment(years, months, days);
 99+      var tmpMoment = createMoment(years, months, days);
100+      if (matches.length >= 9 && matches[8] !== undefined) {
101+        tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
102+      }
103+      m = tmpMoment;
104     }
105   }
106 
107@@ -214,12 +230,13 @@ var DATEVALUE = function (...values) : number {
108   if (m === undefined) {
109     var matches = dateString.match(MONTHDIG_YEAR);
110     if (matches && matches.length >= 6) {
111-      if (matches[6] !== undefined) {
112-        console.log("MONTHDIG_YEAR matched timestamp", matches[6]);
113-      }
114       var years = parseInt(matches[5]);
115       var months = parseInt(matches[3]) - 1; // Months are zero indexed.
116-      m = createMoment(years, months, 0);
117+      var tmpMoment = createMoment(years, months, 0);
118+      if (matches[6] !== undefined) {
119+        tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
120+      }
121+      m = tmpMoment;
122     }
123   }
124 
125@@ -227,9 +244,6 @@ var DATEVALUE = function (...values) : number {
126   if (m === undefined) {
127     var matches = dateString.match(MONTHDIG_DAY_YEAR);
128     if (matches && matches.length >= 8) {
129-      if (matches.length >= 9 && matches[8] !== undefined) {
130-        console.log("MONTHDIG_DAY_YEAR matched timestamp", matches[8]);
131-      }
132       // Check delimiters. If they're not the same, throw error.
133       if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
134         throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
135@@ -237,7 +251,11 @@ var DATEVALUE = function (...values) : number {
136       var years = parseInt(matches[7]);
137       var months = parseInt(matches[3]) - 1; // Months are zero indexed.
138       var days = parseInt(matches[5]) - 1; // Days are zero indexed.
139-      m = createMoment(years, months, days);
140+      var tmpMoment = createMoment(years, months, days);
141+      if (matches.length >= 9 && matches[8] !== undefined) {
142+        tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
143+      }
144+      m = tmpMoment;
145     }
146   }
147 
148@@ -246,12 +264,13 @@ var DATEVALUE = function (...values) : number {
149   if (m === undefined) {
150     var matches = dateString.match(MONTHNAME_YEAR);
151     if (matches && matches.length >= 6) {
152-      if (matches[6] !== undefined) {
153-        console.log("MONTHNAME_YEAR matched timestamp", matches[6]);
154-      }
155       var years = parseInt(matches[5]);
156       var monthName = matches[3];
157-      m = createMoment(years, monthName, 0);
158+      var tmpMoment = createMoment(years, monthName, 0);
159+      if (matches[6] !== undefined) {
160+        tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
161+      }
162+      m = tmpMoment;
163     }
164   }
165 
166@@ -259,9 +278,6 @@ var DATEVALUE = function (...values) : number {
167   if (m === undefined) {
168     var matches = dateString.match(DAY_MONTHNAME_YEAR);
169     if (matches && matches.length >= 8) {
170-      if (matches.length >= 9 && matches[8] !== undefined) {
171-        console.log("DAY_MONTHNAME_YEAR matched timestamp", matches[8]);
172-      }
173       var years = parseInt(matches[7]);
174       var monthName = matches[5];
175       var days = parseInt(matches[3]) - 1; // Days are zero indexed.
176@@ -271,7 +287,11 @@ var DATEVALUE = function (...values) : number {
177       if (firstDelimiter !== secondDelimiter && firstDelimiter !== "") {
178         throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
179       }
180-      m = createMoment(years, monthName, days);
181+      var tmpMoment = createMoment(years, monthName, days);
182+      if (matches.length >= 9 && matches[8] !== undefined) {
183+        tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
184+      }
185+      m = tmpMoment;
186     }
187   }
188 
189@@ -279,12 +299,13 @@ var DATEVALUE = function (...values) : number {
190   if (m === undefined) {
191     var matches = dateString.match(YEAR_MONTHNAME);
192     if (matches && matches.length >= 6) {
193-      if (matches[6] !== undefined) {
194-        console.log("YEAR_MONTHNAME matched timestamp", matches[6]);
195-      }
196       var years = parseInt(matches[3]);
197       var monthName = matches[5];
198-      m = createMoment(years, monthName, 0);
199+      var tmpMoment = createMoment(years, monthName, 0);
200+      if (matches[6] !== undefined) {
201+        tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
202+      }
203+      m = tmpMoment;
204     }
205   }
206 
207diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
208index 3c9635d..b2bfc66 100644
209--- a/src/RawFormulas/Utils.ts
210+++ b/src/RawFormulas/Utils.ts
211@@ -527,7 +527,7 @@ class DateRegExBuilder {
212   }
213 
214   TIMESTAMP_UNITS_CAPTURE_GROUP() : DateRegExBuilder {
215-    this.regexString += "(\\s+([0-9]+)()()\\s*(am|pm)\\s*$)|(\\s+([0-9]+):\\s*([0-9]+)()()\\s*$)|(\\s+(([0-9]+):\\s*([0-9]+)()\\s*(am|pm))\\s*$)|(\\s+(([0-9]+):\\s*([0-9]+):\\s*([0-9]+)())\\s*$)|(\\s+(([0-9]+):\\s*([0-9]+):\\s*([0-9]+)\\s*(am|pm))\\s*$)";
216+    this.regexString += "(\\s*([0-9]+)()()\\s*(am|pm)\\s*$)|(\\s+([0-9]+):\\s*([0-9]+)()()\\s*$)|(\\s+(([0-9]+):\\s*([0-9]+)()\\s*(am|pm))\\s*$)|(\\s+(([0-9]+):\\s*([0-9]+):\\s*([0-9]+)())\\s*$)|(\\s+(([0-9]+):\\s*([0-9]+):\\s*([0-9]+)\\s*(am|pm))\\s*$)";
217     return this;
218   }
219 
220diff --git a/tests/DateFormulasTest.ts b/tests/DateFormulasTest.ts
221index 2b2771b..1a47dfc 100644
222--- a/tests/DateFormulasTest.ts
223+++ b/tests/DateFormulasTest.ts
224@@ -108,7 +108,7 @@ catchAndAssertEquals(function() {
225   DATEVALUE("1/44/2005");
226 }, ERRORS.VALUE_ERROR);
227 // timestamp test
228-assertEquals(DATEVALUE("6-24-92 10am"), 33779); // TODO: come back to these. right now just testing to make sure they don't break anything.
229+assertEquals(DATEVALUE("6-24-92 10am"), 33779);
230 assertEquals(DATEVALUE("6-24-92 10:10"), 33779);
231 assertEquals(DATEVALUE("6-24-92 10:10am"), 33779);
232 assertEquals(DATEVALUE("6-24-92 10:10:10"), 33779);
233@@ -117,7 +117,52 @@ assertEquals(DATEVALUE("6-24-92  10  am"), 33779);
234 assertEquals(DATEVALUE("6-24-92 10: 10 "), 33779);
235 assertEquals(DATEVALUE("6-24-92 10: 10 pm"), 33779);
236 assertEquals(DATEVALUE("6-24-92 10: 10: 10"), 33779);
237-assertEquals(DATEVALUE("6-24-92  10: 1000: 1000    am  "), 33779);
238+assertEquals(DATEVALUE("6-24-92  10: 10: 10    am  "), 33779);
239+assertEquals(DATEVALUE("1992/6/24 00:00"), 33779);
240+assertEquals(DATEVALUE("1992/6/24 0:00"), 33779);
241+assertEquals(DATEVALUE("1992/6/24 10:10"), 33779);
242+assertEquals(DATEVALUE("1992/6/24 16:22"), 33779);
243+assertEquals(DATEVALUE("1992/6/24 25:10"), 33780);
244+assertEquals(DATEVALUE("1992/6/24 23:60"), 33780);
245+assertEquals(DATEVALUE("1992/6/24 24:00"), 33780);
246+assertEquals(DATEVALUE("1992/6/24 23:59"), 33779);
247+assertEquals(DATEVALUE("1999/1/13 10:11111111"), 43889);
248+assertEquals(DATEVALUE("1999/1/13 25000:22"), 37214);
249+assertEquals(DATEVALUE("1999/1/13 25000:    22"), 37214);
250+assertEquals(DATEVALUE("1992/6/24 00:00am"), 33779);
251+assertEquals(DATEVALUE("1992/06/24 01:44am "), 33779);
252+assertEquals(DATEVALUE("1999/1/01 02:59pm"), 36161);
253+assertEquals(DATEVALUE("2222/1/01 03:33pm"), 117610);
254+assertEquals(DATEVALUE("1902/9/02 12:33pm"), 976);
255+assertEquals(DATEVALUE("1902/9/2 12:33pm"), 976);
256+assertEquals(DATEVALUE("4243/11/3 12:33pm"), 856071);
257+assertEquals(DATEVALUE("  1992/04/19   12:  33pm   "), 33713);
258+assertEquals(DATEVALUE("1992/5/20 01:33am"), 33744);
259+assertEquals(DATEVALUE("1992/6/21  3:33pm"), 33776);
260+assertEquals(DATEVALUE("1992/9/29 3:33pm"), 33876);
261+assertEquals(DATEVALUE("1992/1/24 3:33pm"), 33627);
262+assertEquals(DATEVALUE("1992/12/21 3:33pm"), 33959);
263+assertEquals(DATEVALUE("1992/01/31 3:33pm"), 33634);
264+assertEquals(DATEVALUE("1992/1/13 3:33pm"), 33616);
265+assertEquals(DATEVALUE("2004/2/29 3:33pm"), 38046);
266+assertEquals(DATEVALUE("2004/2/28  3:33pm "), 38045);
267+assertEquals(DATEVALUE("1999/1/13 3:33pm"), 36173);
268+assertEquals(DATEVALUE("1999/01/13 3:33pm"), 36173);
269+assertEquals(DATEVALUE("0999/01/13 3:33pm"), -329069);
270+assertEquals(DATEVALUE("1200/01/13 3:33pm"), -255656);
271+assertEquals(DATEVALUE("0029/01/13 3:33pm"), 47131);
272+assertEquals(DATEVALUE("0030/01/13 3:33pm"), 10971);
273+assertEquals(DATEVALUE("0044/01/13 3:33pm"), 16084);
274+assertEquals(DATEVALUE("0050/01/13 3:33pm"), 18276);
275+assertEquals(DATEVALUE("0097/01/13 00:33pm"), 35443);
276+assertEquals(DATEVALUE("0099/01/13 3:33pm"), 36173);
277+assertEquals(DATEVALUE("0000/01/13 3:33pm"), 36538);
278+assertEquals(DATEVALUE("0101/01/13 3:33pm"), -657057);
279+assertEquals(DATEVALUE("0100/01/13 3:33pm"), -657422);
280+assertEquals(DATEVALUE("100/12/31 3:33pm"), -657070);
281+assertEquals(DATEVALUE("122/11/10 3:33pm"), -649086);
282+assertEquals(DATEVALUE("2222/1/22 3:33pm"), 117631);
283+assertEquals(DATEVALUE("222/1/22 3:33pm"), -612854);
284 // YEAR_MONTHDIG_DAY, YYYY(fd)MM(fd)DD =================================================================================
285 assertEquals(DATEVALUE("1992/6/24"), 33779);
286 assertEquals(DATEVALUE("1992/06/24"), 33779);
287@@ -193,7 +238,7 @@ catchAndAssertEquals(function() {
288   DATEVALUE("2005/1/44");
289 }, ERRORS.VALUE_ERROR);
290 // timestamp test
291-assertEquals(DATEVALUE("1992-6-24 10am"), 33779); // TODO: come back to these. right now just testing to make sure they don't break anything.
292+assertEquals(DATEVALUE("1992-6-24 10am"), 33779);
293 assertEquals(DATEVALUE("1992-6-24 10:10"), 33779);
294 assertEquals(DATEVALUE("1992-6-24 10:10am"), 33779);
295 assertEquals(DATEVALUE("1992-6-24 10:10:10"), 33779);
296@@ -202,7 +247,47 @@ assertEquals(DATEVALUE("1992-6-24  10  am"), 33779);
297 assertEquals(DATEVALUE("1992-6-24 10: 10 "), 33779);
298 assertEquals(DATEVALUE("1992-6-24 10: 10 pm"), 33779);
299 assertEquals(DATEVALUE("1992-6-24 10: 10: 10"), 33779);
300-assertEquals(DATEVALUE("1992-6-24  10: 1000: 1000    am   "), 33779);
301+assertEquals(DATEVALUE("1992-6-24  10: 10: 10    am   "), 33779);
302+assertEquals(DATEVALUE("1992/6/24 00am"), 33779);
303+assertEquals(DATEVALUE("1992/06/24 01am "), 33779);
304+assertEquals(DATEVALUE("1999/1/01 02pm"), 36161);
305+assertEquals(DATEVALUE("2222/1/01 03pm"), 117610);
306+assertEquals(DATEVALUE("1902/9/02 12pm"), 976);
307+assertEquals(DATEVALUE("1902/9/2 12pm"), 976);
308+assertEquals(DATEVALUE("4243/11/3 12pm   "), 856071);
309+assertEquals(DATEVALUE("  1992/04/19   12pm   "), 33713);
310+assertEquals(DATEVALUE("1992/5/20 01am"), 33744);
311+assertEquals(DATEVALUE("1992/6/21  3pm"), 33776);
312+assertEquals(DATEVALUE("1992/9/29 3pm"), 33876);
313+assertEquals(DATEVALUE("1992/1/24 3pm"), 33627);
314+assertEquals(DATEVALUE("1992/12/21 3pm"), 33959);
315+assertEquals(DATEVALUE("1992/01/31 3pm"), 33634);
316+assertEquals(DATEVALUE("1992/1/13 3pm"), 33616);
317+assertEquals(DATEVALUE("2004/2/29 3pm"), 38046);
318+assertEquals(DATEVALUE("2004/2/28  3pm "), 38045);
319+assertEquals(DATEVALUE("1999/1/13 3pm"), 36173);
320+assertEquals(DATEVALUE("1999/01/13 3pm"), 36173);
321+assertEquals(DATEVALUE("0999/01/13 3pm"), -329069);
322+assertEquals(DATEVALUE("1200/01/13 3pm"), -255656);
323+assertEquals(DATEVALUE("0029/01/13 3pm"), 47131);
324+assertEquals(DATEVALUE("0030/01/13 3pm"), 10971);
325+assertEquals(DATEVALUE("0044/01/13 3pm"), 16084);
326+assertEquals(DATEVALUE("0050/01/13 3pm"), 18276);
327+assertEquals(DATEVALUE("0097/01/13 00pm"), 35443);
328+assertEquals(DATEVALUE("0099/01/13 3pm"), 36173);
329+assertEquals(DATEVALUE("0000/01/13 3pm"), 36538);
330+assertEquals(DATEVALUE("0101/01/13 3pm"), -657057);
331+assertEquals(DATEVALUE("0100/01/13 3pm"), -657422);
332+assertEquals(DATEVALUE("100/12/31 3pm"), -657070);
333+assertEquals(DATEVALUE("122/11/10 3pm"), -649086);
334+assertEquals(DATEVALUE("2222/1/22 3pm"), 117631);
335+assertEquals(DATEVALUE("222/1/22 3pm"), -612854);
336+catchAndAssertEquals(function() {
337+  DATEVALUE("2005/2/29 000pm");// Too many digits
338+}, ERRORS.VALUE_ERROR);
339+catchAndAssertEquals(function() {
340+  DATEVALUE("2001/2/2 13pm");// Hour out of range
341+}, ERRORS.VALUE_ERROR);
342 // DAY_MONTHNAME_YEAR, DD(fd)Month(fd)YYYY =============================================================================
343 assertEquals(DATEVALUE("Sun 09 Feb 2017"), 42775);
344 assertEquals(DATEVALUE("Sun 9 Feb 2017"), 42775);
345@@ -228,6 +313,30 @@ assertEquals(DATEVALUE("13 January 0099"), 36173);
346 assertEquals(DATEVALUE("13 January 0000"), 36538);
347 assertEquals(DATEVALUE("13 January 0101"), -657057);
348 assertEquals(DATEVALUE("13 January 0100"), -657422);
349+assertEquals(DATEVALUE("01 Jan 2017"), 42736);
350+assertEquals(DATEVALUE("01 Feb 2017"), 42767);
351+assertEquals(DATEVALUE("01 Mar 2017"), 42795);
352+assertEquals(DATEVALUE("01 Apr 2017"), 42826);
353+assertEquals(DATEVALUE("01 May 2017"), 42856);
354+assertEquals(DATEVALUE("01 Jun 2017"), 42887);
355+assertEquals(DATEVALUE("01 Jul 2017"), 42917);
356+assertEquals(DATEVALUE("01 Aug 2017"), 42948);
357+assertEquals(DATEVALUE("01 Sep 2017"), 42979);
358+assertEquals(DATEVALUE("01 Oct 2017"), 43009);
359+assertEquals(DATEVALUE("01 Nov 2017"), 43040);
360+assertEquals(DATEVALUE(" 1 Dec 2017"), 43070);
361+assertEquals(DATEVALUE("20 Jan 2015"), 42024);
362+assertEquals(DATEVALUE("20 Feb 2015"), 42055);
363+assertEquals(DATEVALUE("20 Mar 2015"), 42083);
364+assertEquals(DATEVALUE("20 Apr 2015"), 42114);
365+assertEquals(DATEVALUE("20 May 2015"), 42144);
366+assertEquals(DATEVALUE("20 Jun 2015"), 42175);
367+assertEquals(DATEVALUE("20 Jul 2015"), 42205);
368+assertEquals(DATEVALUE("20 Aug 2015"), 42236);
369+assertEquals(DATEVALUE("20 Sep 2015"), 42267);
370+assertEquals(DATEVALUE("20 Oct 2015"), 42297);
371+assertEquals(DATEVALUE("20 Nov 2015"), 42328);
372+assertEquals(DATEVALUE("20 Dec 2015"), 42358);
373 // delimiter tests
374 assertEquals(DATEVALUE("Sun, 09, Feb, 2017"), 42775);
375 assertEquals(DATEVALUE("Sun, 09/Feb/2017"), 42775);
376@@ -254,7 +363,7 @@ assertEquals(DATEVALUE("24/June/1992  10  am"), 33779);
377 assertEquals(DATEVALUE("24/June/1992 10: 10 "), 33779);
378 assertEquals(DATEVALUE("24/June/1992 10: 10 pm"), 33779);
379 assertEquals(DATEVALUE("24/June/1992 10: 10: 10"), 33779);
380-assertEquals(DATEVALUE("24/June/1992  10: 1000: 1000    am   "), 33779);
381+assertEquals(DATEVALUE("24/June/1992  10: 10: 10    am   "), 33779);
382 // YEAR_MONTHDIG, YYYY(fd)MM, '1992/06' ================================================================================
383 assertEquals(DATEVALUE("2017/01"), 42736);
384 assertEquals(DATEVALUE("2017/02"), 42767);
385@@ -290,7 +399,7 @@ assertEquals(DATEVALUE("2017-01  10  am"), 42736);
386 assertEquals(DATEVALUE("2017-01 10: 10 "), 42736);
387 assertEquals(DATEVALUE("2017-01 10: 10 pm"), 42736);
388 assertEquals(DATEVALUE("2017-01 10: 10: 10"), 42736);
389-assertEquals(DATEVALUE("2017-01  10: 1000: 1000    am   "), 42736);
390+assertEquals(DATEVALUE("2017-01  10: 10: 10    am   "), 42736);
391 // MONTHDIG_YEAR, MM(fd)YYYY, '06/1992' ================================================================================
392 assertEquals(DATEVALUE("01/2017"), 42736);
393 assertEquals(DATEVALUE("02/2017"), 42767);
394@@ -329,7 +438,7 @@ assertEquals(DATEVALUE("01-2017  10  am"), 42736);
395 assertEquals(DATEVALUE("01-2017 10: 10 "), 42736);
396 assertEquals(DATEVALUE("01-2017 10: 10 pm"), 42736);
397 assertEquals(DATEVALUE("01-2017 10: 10: 10"), 42736);
398-assertEquals(DATEVALUE("01-2017  10: 1000: 1000    am   "), 42736);
399+assertEquals(DATEVALUE("01-2017  10: 10: 10    am   "), 42736);
400 // YEAR_MONTHNAME, YYYY(fd)Month, '1992/Aug' ===========================================================================
401 assertEquals(DATEVALUE("2017 January"), 42736);
402 assertEquals(DATEVALUE("2017 February"), 42767);
403@@ -364,7 +473,7 @@ assertEquals(DATEVALUE("2017-January  10  am"), 42736);
404 assertEquals(DATEVALUE("2017-January 10: 10 "), 42736);
405 assertEquals(DATEVALUE("2017-January 10: 10 pm"), 42736);
406 assertEquals(DATEVALUE("2017-January 10: 10: 10"), 42736);
407-assertEquals(DATEVALUE("2017-January  10: 1000: 1000    am   "), 42736);
408+assertEquals(DATEVALUE("2017-January  10: 10: 10    am   "), 42736);
409 // MONTHNAME_YEAR, Month(fd)YYYY, 'Aug 1992' ===========================================================================
410 assertEquals(DATEVALUE("January 2017"), 42736);
411 assertEquals(DATEVALUE("February 2017"), 42767);
412@@ -378,6 +487,15 @@ assertEquals(DATEVALUE("September 2017"), 42979);
413 assertEquals(DATEVALUE("October 2017"), 43009);
414 assertEquals(DATEVALUE("November 2017"), 43040);
415 assertEquals(DATEVALUE("December 2017"), 43070);
416+assertEquals(DATEVALUE("  Feb    2017  "), 42767);
417+assertEquals(DATEVALUE("Feb-2017"), 42767);
418+assertEquals(DATEVALUE("Feb.2017"), 42767);
419+assertEquals(DATEVALUE("Feb/2017"), 42767);
420+assertEquals(DATEVALUE("Feb    .    2017"), 42767);
421+assertEquals(DATEVALUE("Feb -      2017"), 42767);
422+assertEquals(DATEVALUE("January 0030"), 10959);
423+assertEquals(DATEVALUE("November 4243"), 856069);
424+assertEquals(DATEVALUE("December 0100"), -657100);
425 // delimiter tests
426 assertEquals(DATEVALUE("Thursday January 2017"), 42736);
427 assertEquals(DATEVALUE("Thursday, January 2017"), 42736);
428@@ -399,105 +517,18 @@ assertEquals(DATEVALUE("January-2017  10  am"), 42736);
429 assertEquals(DATEVALUE("January-2017 10: 10 "), 42736);
430 assertEquals(DATEVALUE("January-2017 10: 10 pm"), 42736);
431 assertEquals(DATEVALUE("January-2017 10: 10: 10"), 42736);
432-assertEquals(DATEVALUE("January-2017  10: 1000: 1000    am  "), 42736);
433+assertEquals(DATEVALUE("January-2017  10: 10: 10    am  "), 42736);
434+
435+
436+
437+
438+
439+
440+
441 
442 
443 
444 
445-// // YYYY/MM/DD HH(am|pm)
446-// assertEquals(DATEVALUE("1992/6/24 00am"), 33779);
447-// assertEquals(DATEVALUE("1992/06/24 01am "), 33779);
448-// assertEquals(DATEVALUE("1999/1/01 02pm"), 36161);
449-// assertEquals(DATEVALUE("2222/1/01 03pm"), 117610);
450-// assertEquals(DATEVALUE("1902/9/02 12pm"), 976);
451-// assertEquals(DATEVALUE("1902/9/2 12pm"), 976);
452-// assertEquals(DATEVALUE("4243/11/3 12pm   "), 856071);
453-// assertEquals(DATEVALUE("  1992/04/19   12pm   "), 33713);
454-// assertEquals(DATEVALUE("1992/5/20 01am"), 33744);
455-// assertEquals(DATEVALUE("1992/6/21  3pm"), 33776);
456-// assertEquals(DATEVALUE("1992/9/29 3pm"), 33876);
457-// assertEquals(DATEVALUE("1992/1/24 3pm"), 33627);
458-// assertEquals(DATEVALUE("1992/12/21 3pm"), 33959);
459-// assertEquals(DATEVALUE("1992/01/31 3pm"), 33634);
460-// assertEquals(DATEVALUE("1992/1/13 3pm"), 33616);
461-// assertEquals(DATEVALUE("2004/2/29 3pm"), 38046);
462-// assertEquals(DATEVALUE("2004/2/28  3pm "), 38045);
463-// assertEquals(DATEVALUE("1999/1/13 3pm"), 36173);
464-// assertEquals(DATEVALUE("1999/01/13 3pm"), 36173);
465-// assertEquals(DATEVALUE("0999/01/13 3pm"), -329069);
466-// assertEquals(DATEVALUE("1200/01/13 3pm"), -255656);
467-// assertEquals(DATEVALUE("0029/01/13 3pm"), 47131);
468-// assertEquals(DATEVALUE("0030/01/13 3pm"), 10971);
469-// assertEquals(DATEVALUE("0044/01/13 3pm"), 16084);
470-// assertEquals(DATEVALUE("0050/01/13 3pm"), 18276);
471-// assertEquals(DATEVALUE("0097/01/13 00pm"), 35443);
472-// assertEquals(DATEVALUE("0099/01/13 3pm"), 36173);
473-// assertEquals(DATEVALUE("0000/01/13 3pm"), 36538);
474-// assertEquals(DATEVALUE("0101/01/13 3pm"), -657057);
475-// assertEquals(DATEVALUE("0100/01/13 3pm"), -657422);
476-// assertEquals(DATEVALUE("100/12/31 3pm"), -657070);
477-// assertEquals(DATEVALUE("122/11/10 3pm"), -649086);
478-// assertEquals(DATEVALUE("2222/1/22 3pm"), 117631);
479-// assertEquals(DATEVALUE("222/1/22 3pm"), -612854);
480-// catchAndAssertEquals(function() {
481-//   DATEVALUE("2005/2/29 000pm");// Too many digits
482-// }, ERRORS.VALUE_ERROR);
483-// catchAndAssertEquals(function() {
484-//   DATEVALUE("2001/2/2 13pm");// Hour out of range
485-// }, ERRORS.VALUE_ERROR);
486-// catchAndAssertEquals(function() {
487-//   DATEVALUE("2005/2/29 11am");// Leap day on non-leap year.
488-// }, ERRORS.VALUE_ERROR);
489-// catchAndAssertEquals(function() {
490-//   DATEVALUE("2005/1/44 11am");// Out of range day for any month
491-// }, ERRORS.VALUE_ERROR);
492-// // YYYY/MM/DD HH:mm
493-// assertEquals(DATEVALUE("1992/6/24 00:00"), 33779);
494-// assertEquals(DATEVALUE("1992/6/24 0:00"), 33779);
495-// assertEquals(DATEVALUE("1992/6/24 10:10"), 33779);
496-// assertEquals(DATEVALUE("1992/6/24 16:22"), 33779);
497-// assertEquals(DATEVALUE("1992/6/24 25:10"), 33780);
498-// assertEquals(DATEVALUE("1992/6/24 23:60"), 33780);
499-// assertEquals(DATEVALUE("1992/6/24 24:00"), 33780);
500-// assertEquals(DATEVALUE("1992/6/24 23:59"), 33779);
501-// assertEquals(DATEVALUE("1999/1/13 10:11111111"), 43889);
502-// assertEquals(DATEVALUE("1999/1/13 25000:22"), 37214);
503-// assertEquals(DATEVALUE("1999/1/13 25000:    22"), 37214);
504-// // YYYY/MM/DD HH:mm(am|pm)
505-// assertEquals(DATEVALUE("1992/6/24 00:00am"), 33779);
506-// assertEquals(DATEVALUE("1992/06/24 01:44am "), 33779);
507-// assertEquals(DATEVALUE("1999/1/01 02:59pm"), 36161);
508-// assertEquals(DATEVALUE("2222/1/01 03:33pm"), 117610);
509-// assertEquals(DATEVALUE("1902/9/02 12:33pm"), 976);
510-// assertEquals(DATEVALUE("1902/9/2 12:33pm"), 976);
511-// assertEquals(DATEVALUE("4243/11/3 12:33pm"), 856071);
512-// assertEquals(DATEVALUE("  1992/04/19   12:  33pm   "), 33713);
513-// assertEquals(DATEVALUE("1992/5/20 01:33am"), 33744);
514-// assertEquals(DATEVALUE("1992/6/21  3:33pm"), 33776);
515-// assertEquals(DATEVALUE("1992/9/29 3:33pm"), 33876);
516-// assertEquals(DATEVALUE("1992/1/24 3:33pm"), 33627);
517-// assertEquals(DATEVALUE("1992/12/21 3:33pm"), 33959);
518-// assertEquals(DATEVALUE("1992/01/31 3:33pm"), 33634);
519-// assertEquals(DATEVALUE("1992/1/13 3:33pm"), 33616);
520-// assertEquals(DATEVALUE("2004/2/29 3:33pm"), 38046);
521-// assertEquals(DATEVALUE("2004/2/28  3:33pm "), 38045);
522-// assertEquals(DATEVALUE("1999/1/13 3:33pm"), 36173);
523-// assertEquals(DATEVALUE("1999/01/13 3:33pm"), 36173);
524-// assertEquals(DATEVALUE("0999/01/13 3:33pm"), -329069);
525-// assertEquals(DATEVALUE("1200/01/13 3:33pm"), -255656);
526-// assertEquals(DATEVALUE("0029/01/13 3:33pm"), 47131);
527-// assertEquals(DATEVALUE("0030/01/13 3:33pm"), 10971);
528-// assertEquals(DATEVALUE("0044/01/13 3:33pm"), 16084);
529-// assertEquals(DATEVALUE("0050/01/13 3:33pm"), 18276);
530-// assertEquals(DATEVALUE("0097/01/13 00:33pm"), 35443);
531-// assertEquals(DATEVALUE("0099/01/13 3:33pm"), 36173);
532-// assertEquals(DATEVALUE("0000/01/13 3:33pm"), 36538);
533-// assertEquals(DATEVALUE("0101/01/13 3:33pm"), -657057);
534-// assertEquals(DATEVALUE("0100/01/13 3:33pm"), -657422);
535-// assertEquals(DATEVALUE("100/12/31 3:33pm"), -657070);
536-// assertEquals(DATEVALUE("122/11/10 3:33pm"), -649086);
537-// assertEquals(DATEVALUE("2222/1/22 3:33pm"), 117631);
538-// assertEquals(DATEVALUE("222/1/22 3:33pm"), -612854);
539 // assertEquals(DATEVALUE("1992/1/13 6:22222222am"), 49048); // overload minutes
540 // assertEquals(DATEVALUE("1992/1/13 12:720pm"), 33617); // overload minutes
541 // assertEquals(DATEVALUE("1992/1/13 00:720pm"), 33617); // overload minutes
542@@ -629,43 +660,10 @@ assertEquals(DATEVALUE("January-2017  10: 1000: 1000    am  "), 42736);
543 // assertEquals(DATEVALUE("Nov 2017"), 43040);
544 // assertEquals(DATEVALUE("Dec 2017"), 43070);
545 // assertEquals(DATEVALUE("Feb, 2017"), 42767);
546-// assertEquals(DATEVALUE("  Feb    2017  "), 42767);
547-// assertEquals(DATEVALUE("Feb-2017"), 42767);
548-// assertEquals(DATEVALUE("Feb.2017"), 42767);
549-// assertEquals(DATEVALUE("Feb/2017"), 42767);
550-// assertEquals(DATEVALUE("Feb    .    2017"), 42767);
551-// assertEquals(DATEVALUE("Feb -      2017"), 42767);
552-// assertEquals(DATEVALUE("January 0030"), 10959);
553-// assertEquals(DATEVALUE("November 4243"), 856069);
554-// assertEquals(DATEVALUE("December 0100"), -657100);
555 // catchAndAssertEquals(function() {
556 //   DATEVALUE("December 100");// need 4 digits
557 // }, ERRORS.VALUE_ERROR);
558 // catchAndAssertEquals(function() {
559 //   DATEVALUE("Dec.20");// need space if using period
560 // }, ERRORS.VALUE_ERROR);
561-// // DD Month YYYY
562-// assertEquals(DATEVALUE("01 Jan 2017"), 42736);
563-// assertEquals(DATEVALUE("01 Feb 2017"), 42767);
564-// assertEquals(DATEVALUE("01 Mar 2017"), 42795);
565-// assertEquals(DATEVALUE("01 Apr 2017"), 42826);
566-// assertEquals(DATEVALUE("01 May 2017"), 42856);
567-// assertEquals(DATEVALUE("01 Jun 2017"), 42887);
568-// assertEquals(DATEVALUE("01 Jul 2017"), 42917);
569-// assertEquals(DATEVALUE("01 Aug 2017"), 42948);
570-// assertEquals(DATEVALUE("01 Sep 2017"), 42979);
571-// assertEquals(DATEVALUE("01 Oct 2017"), 43009);
572-// assertEquals(DATEVALUE("01 Nov 2017"), 43040);
573-// assertEquals(DATEVALUE(" 1 Dec 2017"), 43070);
574-// assertEquals(DATEVALUE("20 Jan 2015"), 42024);
575-// assertEquals(DATEVALUE("20 Feb 2015"), 42055);
576-// assertEquals(DATEVALUE("20 Mar 2015"), 42083);
577-// assertEquals(DATEVALUE("20 Apr 2015"), 42114);
578-// assertEquals(DATEVALUE("20 May 2015"), 42144);
579-// assertEquals(DATEVALUE("20 Jun 2015"), 42175);
580-// assertEquals(DATEVALUE("20 Jul 2015"), 42205);
581-// assertEquals(DATEVALUE("20 Aug 2015"), 42236);
582-// assertEquals(DATEVALUE("20 Sep 2015"), 42267);
583-// assertEquals(DATEVALUE("20 Oct 2015"), 42297);
584-// assertEquals(DATEVALUE("20 Nov 2015"), 42328);
585-// assertEquals(DATEVALUE("20 Dec 2015"), 42358);
586+//