half-past
Version:
natural-language date-parsing in javascript
336 lines (291 loc) • 8.29 kB
Markdown
<div align="center">
<div>WIP</div>
<a href="https://npmjs.org/package/half-past">
<img src="https://img.shields.io/npm/v/half-past.svg?style=flat-square" />
</a>
<a href="https://unpkg.com/half-past">
<img src="https://badge-size.herokuapp.com/spencermountain/half-past/master/builds/half-past.min.js" />
</a>
</div>
**work-in-progress**
rule-based interpreter for natural-language date-forms.
an opinionated-but-configurable mash-up of [spacetime](https://github.com/spencermountain/spacetime)
and [compromise](https://github.com/spencermountain/compromise)
you've been warned!
### IF YOU DARE:
`npm install half-past`
<!-- ### What it does:
* `"January 8th"` explicit date-forms
* `"1999-12-25"` numeric/ISO date-forms
* `"7:30pm"` NL time-of-day
* `"5pm eastern time"` NL timezone
* `"christmas"` named holidays
* `"next friday"` this/next/last logic
* `"end of the month"` end/start/middle logic
* `between June 5th and 7th` range logic
* `"three days after June 4rth"` 'punt' by a duration
* `this winter` seasons -
* `q2 2020` financial quarters -
* `second semester 2019` academic semesters -
* `every monday` repetitions by interval
* `in April O'neil's house` ignore false-positives
* handle DST/leap-year/hemisphere/leap-second logic (from [spacetime](https://github.com/spencermountain/spacetime) )
* handle tokenization/normalization/punctuation-handling (from [compromise](https://github.com/spencermountain/compromise) )
### What it doesn't do:
* `'easter 1440'` distant dates for astronomical holidays
* `1536602449137` millisecond, or epoch-time as dates
* force interpretation of british/american (always tries both!)
* `sometime in June` decide on a soft-date
* configurable 'last monday' logic -->
### Usage:
```js
var nlp = require('compromise')
var halfPast = require('half-past')
//apply plugin
nlp.plugin(halfPast)
let context = {
// what 'today', or 'now' is
now: '2018-09-10T17:28:32.140Z', // defaults to Date.now()
// our assumed timezone, unless given
timezone: 'Canada/Eastern',
// set our calendar assumptions
days: {
start: '8:00am', // colloquial start/end of a day
end: '6:00pm',
},
weeks: {
start: 'monday', // some disagree.
end: 'friday'
},
casual:{ // amount of time returned in 'after June 5th', etc.
weeks:2
},
holidays: {
'may day': '2018-06-01', // throws-away year info
},
// seasons: [ // defaults to northern-hemisphere (sorry!)
// '2018-03-01', //spring
// '2019-01-01', //summer
// '2019-04-01', //winter
// '2019-07-01', //fall
// ],
// quarters: [
// '2018-01-01', //q1
// '2019-04-01', //q2
// '2019-07-01', //q3
// '2019-09-01', //q4
// ],
// semesters: [ // https://en.wikipedia.org/wiki/Academic_term
// '2018-09-01',
// '2019-01-01',
// '2019-04-01',
// ],
}
let result=halfPast(nlp('june 1st'), context)
/*
[{
start:SpacetimeObject, //you can call .format('iso') or anything you want
end:SpacetimeObject,
precision:'day',
interval:{
unit:'month',
amount:3
},
}]
*/
console.log(result[0].start.format('iso'))
// 2018-06-01T11:18:58.040-04:00
```
### How it works
half-past understands natural language date-forms using the following classification:
#### Single dates:
```
[two days after] [the end of] [next] [thursday] [at 2pm] [EST]
'shift' 'section' 'relative' 'unit' 'time' 'timezone'
[6 hours before] [the start of] [this] [quarter]
```
#### Combined dates
these single-dates can be interpreted as two dates, that share information
```
between [date] and [date]
[date] to [date]
before [date]
after [date]
in [date]
```
<!-- ### Examples:
```
explicit templates
✓ "march 2nd"
✓ "2 march"
✓ "2 march 2016"
✓ "march 2nd"
✓ "2nd of march"
✓ "2nd of march, 2016"
✓ "march 2nd, 2016"
✓ "march 22nd"
✓ "tuesday march 22nd"
✓ "tuesday march 22nd, 2016"
✓ "april the 22nd"
✓ "22 april"
✓ "22 april 2016"
✓ "april 22nd"
✓ "22nd of april"
✓ "the 22nd of april, 2016"
✓ "april 1st, 2016"
✓ "april 1st"
✓ "tuesday, april the 1st"
✓ "tuesday april 1st, 2016"
time-based cruft
✓ "july 5th at 2pm"
✓ "july 5th, 2:12"
✓ "4:23am july 5th "
✓ "july 5th 2pm PST"
✓ "1pm pacific time, july 5th "
✓ "july 5th before noon pacific time"
✓ "3:23 EST july 5th "
✓ "2 oclock july 5th "
✓ "july 5 2016 12 oclock PST"
✓ "3:23 eastern standard time july 5"
named holidays
✓ "new years eve"
✓ "april fools"
✓ "april fools at 5pm"
✓ "april fools, 2016"
numeric dates
✓ "1999/12/25"
✓ "1999-12-25"
✓ "12/25/1999"
✓ "12-25-1999"
✓ "25-12-1999"
✓ "25-12-1999 12:32"
✓ "25-12-1999 12:32:00"
✓ "2016/03/13"
✓ "03/13/2016 at 2:00"
✓ "2016/13/03"
✓ "13/03/2016 before 11"
punted dates
✓ "two days from now"
✓ "in two hours from now"
✓ "two months from today"
✓ "in one year"
✓ "a year from now"
✓ "after a few days"
✓ "in a few years"
✓ "two months later"
✓ "two months in the future"
✓ "a year forward"
adhoc terms
✓ "tomorrow"
✓ "the next day"
✓ "the day after next"
✓ "day after tomorrow"
```
### Relative to now
dates that are relative to given context time
```
relative Year
✓ "q1 2002"
✓ "fourth quarter, 2002"
✓ "fourth quarter"
✓ "spring 2002"
✓ "this march"
✓ next quarter
✓ next year
✓ this winter
✓ middle of the winter
relative Month
✓ "first week of february"
✓ "second week of february"
✓ "2nd week of february"
relative Week
✓ "this saturday"
✓ "sunday"
✓ "mon"
✓ "tuesday"
✓ "next wed"
✓ "this thurs"
✓ "next friday"
✓ "friday"
✓ "this weekend"
✓ "next weekend"
✓ "end of this week"
✓ "next week"
✓ "start of next week"
✓ "end of next week"
✓ "this monday"
✓ "two mondays from now"
✓ "3 mondays from now"
✓ "three sundays from now"
✓ "next monday"
✓ "monday next week"
✓ "the monday after next"
```
### Ranges
```
explicit between range
✓ "between monday and friday"
✓ "between next tuesday and next friday"
✓ "between christmas and new years"
✓ "between new years and christmas"
✓ "from monday to friday"
✓ "from next tuesday to next friday"
✓ "from christmas to new years"
✓ june 5th to august 7th
✓ june 5th to 7th
✓ between june 5 and august seven
now-implicit range (now → then)
✓ "by saturday"
✓ "by tuesday"
✓ "before next spring"
✓ "by 2016-02-06"
duration-implicit range (start → end)
✓ "on friday"
✓ "on next tuesday"
✓ "on christmas"
✓ "on 12/12/1992"
✓ "saturday"
✓ "july 5th"
✓ "july 5th 2016"
✓ "next tuesday"
✓ "tomorrow"
```
### Repeating dates
```
Recurring dates
✓ every day
✓ every thursday
✓ every other day
✓ every other wednesday
✓ each monday at 9am
```
### Calendar-hopping
```
punted dates
✓ 4 days from now
✓ three weeks from today
relative range
✓ two weeks later
Implicit range -- (assumed now-to-then)
✓ by the end of the year
✓ before christmas
soft range - not fully day-defined
✓ middle of the month
✓ start of next week
✓ in august
✓ this spring
punted week with day
✓ two saturdays from now
✓ the friday after next
``` -->
### See also
* [Sugarjs](https://sugarjs.com/dates/) - by Andrew Plummer
* [Chrono](https://github.com/wanasit/chrono) - by Wanasit Tanakitrungruang
* [Datejs](http://www.datejs.com/) - by Geoffrey McGill
#### Other languages
* Clojure - [Duckling](https://duckling.wit.ai/) - by Facebook
* Java - [Natty](http://natty.joestelmach.com/) - by Joe Stelmach
* Go - [When](https://github.com/olebedev/when) - by Oleg Lebedev
* Python - [dateparser](https://github.com/scrapinghub/dateparser) - by ScrapingHub
There are also some excellent commercial services for date-parsing, which we've omitted here.
MIT