travis Codecov Coverage relative-time-expression rte-moment period-edge
This is a expression for relative time. Inspired by Time Units of grafana.
Here is a chinese blog about why I create this library.
npm install rte-moment
npm install relative-time-expression
The expression usually start from "now", like "now", "now-1d". But you can also omit it, like ""(same as "now"), "-1d". After "now", you can append a series of manipulation. There are two types of manipulation, one is offset, the other is period.
- Offset: Add(+) or Subtract(-) to current moment, constructed with op, integer(optional, default
1) and unit(you can check blow). - Period: Point to start(/) or end(\) of period that current moment fall into, constructed with op, integer(optional, default
1) and unit. The custom period (integer larger than 1) are not supported for year and month periods now.
| unit | duration |
|---|---|
| y | year |
| M | month |
| w | week |
| d | day |
| h | hour |
| m | minute |
| s | second |
now - 12h: 12 hours ago, same asmoment().subtract(12, 'hours')-1d: 1 day ago, same asmoment().subtract(1, 'day')now / d: the start of today, same asmoment().startOf('day')now \ w: the end of this week, same asmoment().endOf('week')now - w / w: the start of last week, same asmoment().subtract(1, 'week').startOf('week')+M\M: the end of next month, same asmoment().add(1, 'month').endOf('week')now/4w: Suppose divide time range from unix timestamp zero by4 weeks = 4 * 7 * 24 * 60 * 60 * 1000 ms, and return start of period whichnowfall into.
import parse from 'rte-moment'; const m = parse('now-w/w'); // compatible with grafana, add forceEnd config to make `/` point to end of period const m1 = parse('now-w/w', { forceEnd: true }); import moment from 'moment'; moment().subtract(1, 'week').startOf('week').isSame(m); // true moment().subtract(1, 'week').endOf('week').isSame(m1); // true
If this lib used at server side, you should use timezone from client.
import parse from 'rte-moment'; import moment from 'moment-timezone'; const m = parse('now/d', { base: moment().tz('Asia/Shanghai') }); moment().tz('Asia/Shanghai').startOf('day').isSame(m); // true
You can write binding with any time library.
See moment binding code here.
import { parse } from 'relative-time-expression'; const ast = parse('+M/M'); /* ast { type: 'Expression', start: 0, end: 4, body: [ { type: 'Offset', op: '+', number: 1, unit: 'M', start: 0, end: 2, }, { type: 'Period', op: '/', number: 1, unit: 'M', start: 2, end: 4, } ] } */
import { encode } from 'relative-time-expression'; encode(ast); // return 'now+M/M' encode(ast, { displayOne: true }); // return 'now+1M/M'
import { standardize } from 'relative-time-expression'; standardize(' now - 1 d /w'); // return 'now-d/w' standardize(' now - 1 d /w', { displayOne: true }); // return 'now-1d/w'
Custom period is disabled default. You should enable it manually.
import { parse } from 'relative-time-expression'; parse('+M/4M'); // error! parse('+M/4M', { customPeriod: true }); // success
// parse expression to moment function parseToMoment( exp: string, options?: { forceEnd?: boolean; base?: moment.Moment; customPeriod?: boolean; } ): moment.Moment; // and all api from relative-time-expression
You can check type definitions here.
// parse expression to ast function parse(exp: string, options?: { customPeriod?: boolean; }): Expression; // same as parse function decode(exp: string, options?: { customPeriod?: boolean; }): Expression; // encode ast to expression function encode(exp: InputExpression, options?: { displayOne?: boolean }): string; // same as encode function stringify(exp: InputExpression, options?: { displayOne?: boolean }): string; // format expression as standard function standardize(exp: string, options?: { displayOne?: boolean }): string;
The grammar is simple:
<expression> ::= [<ws>] [now] *([<ws>] <relative> [<ws>])
<relative> ::= <offset> | <period>
<offset> ::= (+ | -) <ws> [<number>] <ws> <unit>
<period> ::= (/ | \) <ws> [<number>] <ws> <unit>
<number> ::= ('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') [<number>]
<unit> ::= 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'y'
<ws> ::= ' ' | '\r' | '\n' | '\t' [<ws>]