Skip to content
Browse files

Provide a way to bias the dates parsed to either the past or the future

Biasing is signaled by setting the `bias` property to `past` or `future`
on an object that is passed as the second optional argument to
`Date.parse()`.
  • Loading branch information...
1 parent 327aa38 commit 7531a3d5a4acf81042332a18466596420ba6cac7 @eric eric committed
Showing with 211 additions and 14 deletions.
  1. +17 −0 README.md
  2. +35 −13 src/parser.js
  3. +159 −1 test/partial/index.js
View
17 README.md
@@ -23,6 +23,23 @@ This isn't a comprehesive list, but it hopefully will hit the high points.
* Adding comments to `finish()` in `parser.js` to describe what each condition does
* Remove conditions in `finish()` in `parser.js` that are not used by any tests
* Fix a couple relative-ish cases like `15th at 3pm`
+* Added support for "biasing" toward dates in the past or the future
+
+
+## Biasing ##
+
+There are many times where your users will be tending to want to specify dates
+only in the past or the future, so providing a mechanism where, if it is
+`3pm` in the afternoon, specifying `1pm` would give you the next day instead
+of the current one.
+
+To enable biasing, `Date.parse()` now takes an optional object that is used
+as the object that is parsed to set defaults.
+
+To enable biasing, set the `bias` property to either `past` or `future`. For
+example:
+
+ Date.parse('3pm', { bias: 'future' })
## Original README.txt ##
View
48 src/parser.js
@@ -634,10 +634,10 @@
today = new Date();
}
- var expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ var expression = !!(this.days && this.days !== null || this.orient || this.operator || this.bias);
var gap, mod, orient;
- orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1);
+ orient = ((this.orient == "past" || this.operator == "subtract" || this.bias == "past") ? -1 : 1);
// For parsing: "last second", "next minute", "previous hour", "+5 seconds",
// "-5 hours", "5 hours", "7 hours ago"
@@ -679,7 +679,7 @@
// For parsing: "last january", "prev march", "next july", "today + 1 month",
// "+5 months"
- if (expression && (this.month || this.month === 0) && this.unit != "year") {
+ if ((expression && !this.bias) && (this.month || this.month === 0) && this.unit != "year") {
this.unit = "month";
gap = (this.month - today.getMonth());
mod = 12;
@@ -687,10 +687,10 @@
this.month = null;
}
- // For parsing: "Yesterday", "Tomorrow", "last monday", "last friday",
- // "previous day", "next week", "next month", "next year",
+ // For parsing: "last monday", "last friday", "previous day",
+ // "next week", "next month", "next year",
// "today+", "+", "-", "yesterday at 4:00", "last friday at 20:00"
- if (!this.value && expression) {
+ if (!this.value && expression && !this.bias) {
this.value = 1;
}
@@ -700,9 +700,9 @@
}
// For parsing: "15th at 20:15", "15th at 8pm"
- if (!expression && this.value && (!this.unit || this.unit == "day") && !this.day) {
+ if ((!expression || this.bias) && this.value && (!this.unit || this.unit == "day") && !this.day) {
this.unit = "day";
- this.day = this.value * orient;
+ this.day = this.value * 1
}
// For parsing: "last minute", "+5 hours", "previous month", "1 year ago tomorrow"
@@ -741,6 +741,28 @@
today.set(this);
+ if (this.bias) {
+ if (this.day) {
+ this.days = null
+ }
+
+ if (!this.day) {
+ if ((this.bias == "past" && today > new Date()) || (this.bias == "future" && today < new Date())) {
+ this.days = 1 * orient
+ }
+ } else if (!this.month && !this.months) {
+ if ((this.bias == "past" && today > new Date()) || (this.bias == "future" && today < new Date())) {
+ this.months = 1 * orient
+ }
+ } else if (!this.year) {
+ if ((this.bias == "past" && today > new Date()) || (this.bias == "future" && today < new Date())) {
+ this.years = 1 * orient
+ }
+ }
+
+ expression = true;
+ }
+
if (expression) {
today.add(this);
}
@@ -1082,12 +1104,12 @@
}
if (!o) {
o = {}
- }
- // try {
+ }
+ try {
r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"), o);
- // } catch (e) {
- // return null;
- // }
+ } catch (e) {
+ return null;
+ }
return ((r[1].length === 0) ? r[0] : null);
};
View
160 test/partial/index.js
@@ -1104,7 +1104,165 @@
return false;
}
}
+ },
+ 'Biasing': {
+ 'biasing to the past, parse 1am': {
+ run: function() { this.date = Date.parse('12:01am', { bias: 'past' }) },
+ assert: function() { return this.date < new Date() }
+ },
+ 'biasing to the past, parse 11pm': {
+ run: function() { this.date = Date.parse('11:59pm', { bias: 'past' }) },
+ assert: function() { return this.date < new Date() }
+ },
+ 'biasing to the past, parse a time an hour ahead of now': {
+ run: function() {
+ this.nextHour = new Date().next().hour()
+ this.date = Date.parse(String(this.nextHour.getHours()) + ":" + String(this.nextHour.getMinutes()), { bias: 'past' })
+ },
+ assert: function() {
+ // The date is less than today
+ return this.date < new Date() &&
+ // and the hour is the hour we told it to be
+ this.date.getHours() == this.nextHour.getHours() &&
+ // and the day is yesterday
+ new Date().previous().day().same().day(this.date);
+ }
+ },
+
+ 'biasing to the past, parse a time an hour behind now': {
+ run: function() {
+ this.nextHour = new Date().previous().hour()
+ this.date = Date.parse(String(this.nextHour.getHours()) + ":" + String(this.nextHour.getMinutes()), { bias: 'past' })
+ },
+ assert: function() {
+ // The date is less than today
+ return this.date < new Date() &&
+ // and the hour is the hour we told it to be
+ this.date.getHours() == this.nextHour.getHours() &&
+ // and the day is yesterday
+ new Date().same().day(this.date);
+ }
+ },
+
+ 'biasing to the past, parse tomorrows day of the week to last week': {
+ run: function() {
+ this.nextDay = new Date().next().day()
+ this.date = Date.parse(this.nextDay.toString("dddd") + " at 3pm", { bias: 'past' })
+ },
+ assert: function() {
+ // The date is less than now
+ return this.date < new Date() &&
+ // and the hour is 3pm
+ this.date.getHours() == 15;
+ }
+ },
+
+ 'biasing to the past, parse the day of the month tomorrow to last month': {
+ run: function() {
+ this.nextDay = new Date().next().day()
+ this.date = Date.parse(this.nextDay.toString("dS") + " at 3pm", { bias: 'past' })
+ },
+ assert: function() {
+ // The date is less than now
+ return this.date < new Date() &&
+ // and the hour is 3pm
+ this.date.getHours() == 15 &&
+ // make sure the day of the month is right
+ this.date.getDate() == this.nextDay.getDate();
+ }
+ },
+
+ 'biasing to the past, parse the day and the month of next month to a year ago': {
+ run: function() {
+ this.nextMonth = new Date().next().month()
+ this.date = Date.parse(this.nextMonth.toString("MMMM dS") + " at 3pm", { bias: 'past' })
+ },
+ assert: function() {
+ // The date is less than now
+ return this.date < new Date() &&
+ // and the hour is 3pm
+ this.date.getHours() == 15 &&
+ // make sure the day of the month is right
+ this.date.getDate() == this.nextMonth.getDate();
+ }
+ },
+
+ 'biasing to the future, parse a time an hour behind now': {
+ run: function() {
+ this.previousHour = new Date().previous().hour()
+ this.date = Date.parse(String(this.previousHour.getHours()) + ":" + String(this.previousHour.getMinutes()), { bias: 'future' })
+ },
+ assert: function() {
+ // The date is greater than now
+ return this.date > new Date() &&
+ // and the hour is the hour we told it to be
+ this.date.getHours() == this.previousHour.getHours() &&
+ // and the day is yesterday
+ new Date().next().day().same().day(this.date);
+ }
+ },
+
+ 'biasing to the future, parse a time an hour ahead of now': {
+ run: function() {
+ this.nextHour = new Date().next().hour()
+ this.date = Date.parse(String(this.nextHour.getHours()) + ":" + String(this.nextHour.getMinutes()), { bias: 'future' })
+ },
+ assert: function() {
+ // The date is greater than now
+ return this.date > new Date() &&
+ // and the hour is the hour we told it to be
+ this.date.getHours() == this.nextHour.getHours() &&
+ // and the day is yesterday
+ new Date().same().day(this.date);
+ }
+ },
+
+
+ 'biasing to the future, parse yesterdays day of the week to next week': {
+ run: function() {
+ this.previousDay = new Date().previous().day()
+ this.date = Date.parse(this.previousDay.toString("dddd") + " at 3pm", { bias: 'future' })
+ },
+ assert: function() {
+ // The date is greater than now
+ return this.date > new Date() &&
+ // and the hour is 3pm
+ this.date.getHours() == 15;
+ }
+ },
+
+ 'biasing to the future, parse the day of the month for yesterday to next month': {
+ run: function() {
+ this.previousDay = new Date().previous().day()
+ this.query = this.previousDay.toString("dS") + " at 3pm"
+ this.date = Date.parse(this.query, { bias: 'future' })
+ },
+ assert: function() {
+ // The date is greater than now
+ return this.date > new Date() &&
+ // and the hour is 3pm
+ this.date.getHours() == 15 &&
+ // make sure the day of the month is right
+ this.date.getDate() == this.previousDay.getDate();
+ }
+ },
+
+ 'biasing to the future, parse the day and the month of last month to a year from now': {
+ run: function() {
+ this.lastMonth = new Date().last().month()
+ this.query = this.lastMonth.toString("MMMM dS") + " at 3pm"
+ this.date = Date.parse(this.query, { bias: 'future' })
+ },
+ assert: function() {
+ // The date is greater than now
+ return this.date > new Date() &&
+ // and the hour is 3pm
+ this.date.getHours() == 15 &&
+ // make sure the day of the month is right
+ this.date.getDate() == this.lastMonth.getDate();
+ }
+ },
+
}
-
});

0 comments on commit 7531a3d

Please sign in to comment.
Something went wrong with that request. Please try again.