spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
work-in-progress on overloading the timestamps to shift datevalues up or down
author
Ben Vogt <[email protected]>
date
2017-04-01 20:33:18
stats
3 file(s) changed, 88 insertions(+), 12 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 879781d..53b61ae 100644
  3--- a/src/RawFormulas/Date.ts
  4+++ b/src/RawFormulas/Date.ts
  5@@ -78,6 +78,12 @@ const MONTHNAME_YEAR = DateRegExBuilder.DateRegExBuilder()
  6   .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MONTHNAME().FLEX_DELIMITER().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
  7   .end()
  8   .build();
  9+// For reference: https://regex101.com/r/47GARA/1/
 10+const TIMESTAMP = DateRegExBuilder.DateRegExBuilder()
 11+  .start()
 12+  .TIMESTAMP_UNITS_CAPTURE_GROUP()
 13+  .end()
 14+  .build();
 15 
 16 
 17 /**
 18@@ -95,7 +101,14 @@ var DATEVALUE = function (...values) : number {
 19   var dateString = TypeCaster.firstValueAsString(values[0]);
 20   var m;
 21 
 22-  function createMoment(years, months, days) {
 23+  /**
 24+   * Creates moment object from years, months and days.
 25+   * @param years of moment
 26+   * @param months of moment in number or string format (eg: January)
 27+   * @param days of moment
 28+   * @returns {Moment} created moment
 29+   */
 30+  function createMoment(years, months, days) : moment.Moment {
 31     var actualYear = years;
 32     if (years >= 0 && years < 30) {
 33       actualYear = Y2K_YEAR + years;
 34@@ -115,17 +128,66 @@ var DATEVALUE = function (...values) : number {
 35     return tmpMoment.add(days, 'days');
 36   }
 37 
 38+  /**
 39+   *
 40+   * @param timestampString
 41+   * @param momentToMutate
 42+   * @returns {moment.Moment}
 43+   */
 44+  function matchTimestampAndMutateMoment(timestampString : string, momentToMutate: moment.Moment) : moment.Moment {
 45+    var matches = timestampString.match(TIMESTAMP);
 46+    if (matches && matches[1] !== undefined) { // 10am
 47+      var hours = parseInt(matches[2]);
 48+      var amTrue = (matches[5].toLowerCase() === "am");
 49+      if (hours > 12) {
 50+        throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 51+      }
 52+      // No op on momentToMutate because you can't overload hours with am/pm.
 53+    } if (matches && matches[6] !== undefined) { // 10:10
 54+      var hours = parseInt(matches[7]);
 55+      var minutes = parseInt(matches[8]);
 56+      momentToMutate.add(hours, 'hours').add(minutes, 'minutes');
 57+    } if (matches && matches[11] !== undefined) { // 10:10am
 58+      var hours = parseInt(matches[13]);
 59+      var minutes = parseInt(matches[14]);
 60+      var amTrue = (matches[16].toLowerCase() === "am");
 61+      if (hours > 12) {
 62+        throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 63+      }
 64+      momentToMutate.add(hours, 'hours').add(minutes, 'minutes'); // TODO: don't I add or remove 12 hours?
 65+    } if (matches && matches[17] !== undefined) { // 10:10:10
 66+      var hours = parseInt(matches[19]);
 67+      var minutes = parseInt(matches[20]);
 68+      var seconds = parseInt(matches[21]);
 69+      momentToMutate.add(hours, 'hours').add(minutes, 'minutes').add(seconds, 'seconds');
 70+    } if (matches && matches[23] !== undefined) { // // 10:10:10am
 71+      var hours = parseInt(matches[25]);
 72+      var minutes = parseInt(matches[26]);
 73+      var seconds = parseInt(matches[27]);
 74+      var amTrue = (matches[28].toLowerCase() === "am");
 75+      if (hours > 12) {
 76+        throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 77+      }
 78+      momentToMutate.add(hours, 'hours').add(minutes, 'minutes').add(seconds, 'seconds');
 79+    } else {
 80+      // TODO: Throw error if no match found by now.
 81+    }
 82+    return momentToMutate;
 83+  }
 84+
 85   // Check YEAR_MONTHDIG, YYYY(fd)MM, '1992/06'
 86   // NOTE: Must come before YEAR_MONTHDIG_DAY matching.
 87   if (m === undefined) {
 88     var matches = dateString.match(YEAR_MONTHDIG);
 89     if (matches && matches.length >= 6) {
 90+      var years = parseInt(matches[3]);
 91+      var months = parseInt(matches[5]) - 1; // Months are zero indexed.
 92+      var tmpMoment = createMoment(years, months, 0);
 93       if (matches[6] !== undefined) {
 94         console.log("YEAR_MONTHDIG matched timestamp", matches[6]);
 95+        tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
 96       }
 97-      var years = parseInt(matches[3]);
 98-      var months = parseInt(matches[5]) - 1; // Months are zero indexed.
 99-      m = createMoment(years, months, 0);
100+      m = tmpMoment;
101     }
102   }
103 
104diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
105index 262431f..3c9635d 100644
106--- a/src/RawFormulas/Utils.ts
107+++ b/src/RawFormulas/Utils.ts
108@@ -526,6 +526,11 @@ class DateRegExBuilder {
109     return this;
110   }
111 
112+  TIMESTAMP_UNITS_CAPTURE_GROUP() : DateRegExBuilder {
113+    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*$)";
114+    return this;
115+  }
116+
117   /**
118    * Build the regular expression and ignore case.
119    * @returns {RegExp}
120diff --git a/tests/DateFormulasTest.ts b/tests/DateFormulasTest.ts
121index db8fdea..2b2771b 100644
122--- a/tests/DateFormulasTest.ts
123+++ b/tests/DateFormulasTest.ts
124@@ -117,7 +117,7 @@ assertEquals(DATEVALUE("6-24-92  10  am"), 33779);
125 assertEquals(DATEVALUE("6-24-92 10: 10 "), 33779);
126 assertEquals(DATEVALUE("6-24-92 10: 10 pm"), 33779);
127 assertEquals(DATEVALUE("6-24-92 10: 10: 10"), 33779);
128-assertEquals(DATEVALUE("6-24-92  101120: 10: 10    am  "), 33779);
129+assertEquals(DATEVALUE("6-24-92  10: 1000: 1000    am  "), 33779);
130 // YEAR_MONTHDIG_DAY, YYYY(fd)MM(fd)DD =================================================================================
131 assertEquals(DATEVALUE("1992/6/24"), 33779);
132 assertEquals(DATEVALUE("1992/06/24"), 33779);
133@@ -202,7 +202,7 @@ assertEquals(DATEVALUE("1992-6-24  10  am"), 33779);
134 assertEquals(DATEVALUE("1992-6-24 10: 10 "), 33779);
135 assertEquals(DATEVALUE("1992-6-24 10: 10 pm"), 33779);
136 assertEquals(DATEVALUE("1992-6-24 10: 10: 10"), 33779);
137-assertEquals(DATEVALUE("1992-6-24  101120: 10: 10    am  "), 33779);
138+assertEquals(DATEVALUE("1992-6-24  10: 1000: 1000    am   "), 33779);
139 // DAY_MONTHNAME_YEAR, DD(fd)Month(fd)YYYY =============================================================================
140 assertEquals(DATEVALUE("Sun 09 Feb 2017"), 42775);
141 assertEquals(DATEVALUE("Sun 9 Feb 2017"), 42775);
142@@ -254,7 +254,7 @@ assertEquals(DATEVALUE("24/June/1992  10  am"), 33779);
143 assertEquals(DATEVALUE("24/June/1992 10: 10 "), 33779);
144 assertEquals(DATEVALUE("24/June/1992 10: 10 pm"), 33779);
145 assertEquals(DATEVALUE("24/June/1992 10: 10: 10"), 33779);
146-assertEquals(DATEVALUE("24/June/1992  101120: 10: 10    am  "), 33779);
147+assertEquals(DATEVALUE("24/June/1992  10: 1000: 1000    am   "), 33779);
148 // YEAR_MONTHDIG, YYYY(fd)MM, '1992/06' ================================================================================
149 assertEquals(DATEVALUE("2017/01"), 42736);
150 assertEquals(DATEVALUE("2017/02"), 42767);
151@@ -290,7 +290,7 @@ assertEquals(DATEVALUE("2017-01  10  am"), 42736);
152 assertEquals(DATEVALUE("2017-01 10: 10 "), 42736);
153 assertEquals(DATEVALUE("2017-01 10: 10 pm"), 42736);
154 assertEquals(DATEVALUE("2017-01 10: 10: 10"), 42736);
155-assertEquals(DATEVALUE("2017-01  101120: 10: 10    am  "), 42736);
156+assertEquals(DATEVALUE("2017-01  10: 1000: 1000    am   "), 42736);
157 // MONTHDIG_YEAR, MM(fd)YYYY, '06/1992' ================================================================================
158 assertEquals(DATEVALUE("01/2017"), 42736);
159 assertEquals(DATEVALUE("02/2017"), 42767);
160@@ -329,7 +329,7 @@ assertEquals(DATEVALUE("01-2017  10  am"), 42736);
161 assertEquals(DATEVALUE("01-2017 10: 10 "), 42736);
162 assertEquals(DATEVALUE("01-2017 10: 10 pm"), 42736);
163 assertEquals(DATEVALUE("01-2017 10: 10: 10"), 42736);
164-assertEquals(DATEVALUE("01-2017  101120: 10: 10    am  "), 42736);
165+assertEquals(DATEVALUE("01-2017  10: 1000: 1000    am   "), 42736);
166 // YEAR_MONTHNAME, YYYY(fd)Month, '1992/Aug' ===========================================================================
167 assertEquals(DATEVALUE("2017 January"), 42736);
168 assertEquals(DATEVALUE("2017 February"), 42767);
169@@ -364,7 +364,7 @@ assertEquals(DATEVALUE("2017-January  10  am"), 42736);
170 assertEquals(DATEVALUE("2017-January 10: 10 "), 42736);
171 assertEquals(DATEVALUE("2017-January 10: 10 pm"), 42736);
172 assertEquals(DATEVALUE("2017-January 10: 10: 10"), 42736);
173-assertEquals(DATEVALUE("2017-January  101120: 10: 10    am  "), 42736);
174+assertEquals(DATEVALUE("2017-January  10: 1000: 1000    am   "), 42736);
175 // MONTHNAME_YEAR, Month(fd)YYYY, 'Aug 1992' ===========================================================================
176 assertEquals(DATEVALUE("January 2017"), 42736);
177 assertEquals(DATEVALUE("February 2017"), 42767);
178@@ -399,7 +399,7 @@ assertEquals(DATEVALUE("January-2017  10  am"), 42736);
179 assertEquals(DATEVALUE("January-2017 10: 10 "), 42736);
180 assertEquals(DATEVALUE("January-2017 10: 10 pm"), 42736);
181 assertEquals(DATEVALUE("January-2017 10: 10: 10"), 42736);
182-assertEquals(DATEVALUE("January-2017  101120: 10: 10    am  "), 42736);
183+assertEquals(DATEVALUE("January-2017  10: 1000: 1000    am  "), 42736);
184 
185 
186