Skip to content

Commit

Permalink
Adding support for datetime
Browse files Browse the repository at this point in the history
  • Loading branch information
aholstenson committed Jan 29, 2017
1 parent d87632c commit a038b77
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 166 deletions.
43 changes: 38 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Capture any positive integer number.

Language | Examples
-----------------|-------------
English | `20`, `zero`, `one million`, `4 000`, '1 dozen', '100k'
English | `20`, `zero`, `one million`, `4 000`, `1 dozen`, `100k`

#### Returned value

Expand Down Expand Up @@ -101,7 +101,7 @@ Capture any number, including numbers with a fractional element.

Language | Examples
-----------------|-------------
English | `20`, `2.4 million`, `8.0`, '-12'
English | `20`, `2.4 million`, `8.0`, `-12`

#### Returned value

Expand All @@ -128,7 +128,7 @@ Capture an ordinal, such as `1st`, indicating a position.

Language | Examples
-----------------|-------------
English | `1st`, `third`, `3`, 'the fifth'
English | `1st`, `third`, `3`, `the fifth`

#### Returned value

Expand Down Expand Up @@ -159,8 +159,13 @@ English | `today`, `in 2 days`, `january 12th`, `2010-02-22`, `02/22/20

#### Returned value

The returned value is an object with the keys `year`, `month`, `day` and a
parsed date ``
The returned value is an object with the keys `year`, `month`, `day` and can
be turned into a `Date` via the function `toDate`.

```javascript
const date = value.toDate();
```

#### Example

```javascript
Expand All @@ -180,6 +185,17 @@ Language | Examples
-----------------|-------------
English | `09:00`, `3 pm`, `at 3:30 am`, `noon`, `quarter to twelve`, `in 2 hours`, `in 45 minutes`

#### Returned value

The returned value is an object with the keys `hour`, `minute`, `second` and can
be turned into a `Date` via the function `toDate`.

```javascript
const date = value.toDate();
```

#### Example

```javascript
const time = require('ecolect/values/time');

Expand All @@ -189,6 +205,23 @@ builder.intent('alarm')
.done();
```

### Date & Time

Capture both a date and a time.

Language | Examples
-----------------|-------------
English | `3pm on Jan 12th`, `in 2 days and 2 hours`, `14:00`

```javascript
const datetime = require('ecolect/values/datetime');

builder.intent('schedule')
.value('when', datetime())
.add('Schedule a call {when}')
.done();
```

### Enumeration

Capture one of the specified values. Used to specify one or more values that
Expand Down
176 changes: 136 additions & 40 deletions language/dates.js
Original file line number Diff line number Diff line change
@@ -1,91 +1,187 @@
'use strict';

module.exports.currentTime = function(encounter) {
const cloneDeep = require('lodash.clonedeep');

const addMonths = require('date-fns/add_months')
const addWeeks = require('date-fns/add_weeks');
const addDays = require('date-fns/add_days')
const addSeconds = require('date-fns/add_seconds')

const setISODay = require('date-fns/set_iso_day');
const getISODay = require('date-fns/get_iso_day');
const setHours = require('date-fns/set_hours')
const setMinutes = require('date-fns/set_minutes')
const setSeconds = require('date-fns/set_seconds')

module.exports.isRelative = function isRelative(v) {
return v && (v.relativeMonths >= 0 || v.relativeWeeks >= 0 || v.relativeDays >= 0);
};

module.exports.combine = function(a, b) {
const result = cloneDeep(a);
Object.keys(b).forEach(key => result[key] = b[key]);
return result;
};

function currentTime(encounter) {
if(encounter.options.now) {
return encounter.options.now;
} else {
return encounter.options.now = new Date();
}
};
}
module.exports.currentTime = currentTime;

module.exports.toDate = function toDate(date, now) {
function toDate(date, now) {
return new Date(
typeof date.year !== 'undefined' ? date.year : now.getFullYear(),
typeof date.month !== 'undefined' ? date.month : now.getMonth(),
typeof date.day !== 'undefined' ? date.day : now.getDate()
);
};
}

module.exports.mapYear = function(r, e) {
module.exports.toDate = toDate;

function mapYear(r, e) {
const now = module.exports.currentTime(e);
if(r.adjusters) {
r.adjusters.forEach(a => a(r, now));
}

const result = {};
const result = new DateValue(e.language);

if(typeof r.relativeYear !== 'undefined') {
result.year = now.getFullYear() + r.relativeYear;
result.month = now.getMonth();
}

if(typeof r.relativeMonths !== 'undefined') {
const time = addMonths(toDate(result, now), r.relativeMonths);
result.year = time.getFullYear();
result.month = time.getMonth();
}

if(typeof r.year !== 'undefined') {
result.year = r.year;
}

if(typeof r.month !== 'undefined') {
result.month = r.month;
}

return new DateValue(e.language, result);
};
return result;
}

module.exports.mapMonth = module.exports.mapYear;
module.exports.mapYear = mapYear;
module.exports.mapMonth = mapYear;

module.exports.mapDate = function(r, e) {
const now = module.exports.currentTime(e);
if(r.adjusters) {
r.adjusters.forEach(a => a(r, now));
}
function resolveDate(r, e) {
const result = mapYear(r, e);

const result = {};
if(typeof r.year !== 'undefined') {
result.year = r.year;
} else {
const now = toDate(result, currentTime(e));

if(typeof result.year === 'undefined') {
result.year = now.getFullYear();
}
if(typeof r.month !== 'undefined') {
result.month = r.month;
} else {

if(typeof result.month === 'undefined') {
result.month = now.getMonth();
}
if(typeof r.day !== 'undefined') {
result.day = r.day;

if(typeof r.relativeDays !== 'undefined') {
const date = addDays(toDate(result, now), r.relativeDays);
result.year = date.getFullYear();
result.month = date.getMonth();
result.day = date.getDate();
} else {
result.day = now.getDate();
if(typeof r.day !== 'undefined') {
result.day = r.day;
} else {
result.day = now.getDate();
}
}


if(typeof r.dayOfWeek !== 'undefined') {
result.dayOfWeek = r.dayOfWeek;
if(typeof r.month === 'undefined') {
// Reset to first month
result.month = 0;
}

if(typeof r.day === 'undefined') {
// Reset to first day
result.day = 1;
}

let date = toDate(result, now);

const currentDayOfWeek = getISODay(date);
if(currentDayOfWeek > r.dayOfWeek) {
date = addWeeks(date, 1);
}
date = setISODay(date, r.dayOfWeek);

for(let i=1; i<r.dayOfWeekOrdinal; i++) {
date = addWeeks(date, 1);
}

result.year = date.getFullYear();
result.month = date.getMonth();
result.day = date.getDate();
}

return new DateValue(e.language, result);
};
return result;
}

module.exports.mapDate = resolveDate;

function resolveTime(r, e, now, result) {
result = result || new DateValue(e.language);

let time = currentTime(e);

if(r.relative > 0) {
time = addSeconds(time, r.relative);
} else {
if(typeof r.hour !== 'undefined') {
time = setHours(time, r.hour);
}

function copy(from, to, value) {
if(typeof from[value] !== 'undefined') {
to[value] = from[value];
if(typeof r.minute !== 'undefined') {
time = setMinutes(time, r.minute);
} else {
time = setMinutes(time, 0);
}

if(typeof r.second !== 'undefined') {
time = setSeconds(time, r.second);
} else {
time = setSeconds(time, 0);
}
}

result.hour = time.getHours();
result.minute = time.getMinutes();
result.precision = r.precision || result.precision || 'normal';
return result;
}

class DateValue {
constructor(language, data) {
copy(data, this, 'year');
copy(data, this, 'month');
copy(data, this, 'day');
module.exports.mapTime = resolveTime;

copy(data, this, 'hour');
copy(data, this, 'minute');
copy(data, this, 'second');
module.exports.mapDateTime = function(r, e) {
const result = resolveDate(r, e);

return resolveTime(r, e, result.toDate(), result);
}

class DateValue {
constructor(language) {
Object.defineProperty(this, 'language', {
value: language
});
}

toDate() {
return module.exports.toDate(this, new Date());
toDate(now) {
return module.exports.toDate(this, now || new Date());
}
}
8 changes: 5 additions & 3 deletions language/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const utils = require('./utils');

const dateLocale = require('date-fns/locale/en');
//const dateLocale = require('date-fns/locale/en');

const integer = require('./en/integer');
const number = require('./en/number');
Expand All @@ -15,6 +15,7 @@ const month = require('./en/month');
const year = require('./en/year');
const date = require('./en/date');
const time = require('./en/time');
const datetime = require('./en/datetime');

const stemmer = require('talisman/stemmers/porter');
const similarity = require('talisman/metrics/distance/jaro-winkler').similarity;
Expand Down Expand Up @@ -84,10 +85,10 @@ module.exports = {
compareTokens(a, b) {
if(a.normalized === b.normalized) return 1.0;

if(a.short || b.short) return 0;

if(a.stemmed === b.stemmed) return 0.95;

if(a.short || b.short) return 0;

const d = similarity(a.normalized, b.normalized);
if(d > 0.9) return d * 0.9;

Expand All @@ -114,5 +115,6 @@ module.exports.month = month(module.exports);
module.exports.year = year(module.exports);
module.exports.date = date(module.exports);
module.exports.time = time(module.exports);
module.exports.datetime = datetime(module.exports);

module.exports.temperature = temperature(module.exports);
Loading

0 comments on commit a038b77

Please sign in to comment.