Skip to content

Commit

Permalink
Merge pull request #26 from tolu/update-deps
Browse files Browse the repository at this point in the history
Port to TypeScript
  • Loading branch information
tolu authored Apr 13, 2022
2 parents b39ac80 + a71bcf5 commit daa03c9
Show file tree
Hide file tree
Showing 15 changed files with 424 additions and 445 deletions.
3 changes: 0 additions & 3 deletions .babelrc

This file was deleted.

12 changes: 12 additions & 0 deletions .github/workflows/pr-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Run Tests
on: [pull_request]
jobs:
Npm-Install-And-Test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 'lts/*'
- run: npm install
- run: npm test
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib
20 changes: 0 additions & 20 deletions .travis.yml

This file was deleted.

75 changes: 39 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
# ISO8601-duration

Node/Js-module for parsing and making sense of ISO8601-durations

[![Build Status: Travis](https://img.shields.io/travis/tolu/ISO8601-duration/master.svg)][travis]
[![npm version](https://img.shields.io/npm/v/iso8601-duration.svg)][npm]
![npm bundle size][bundlephobia]

> A new standard is on it's way, see [Temporal.Duration](https://tc39.es/proposal-temporal/docs/duration.html)
## The ISO8601 duration format

Durations in ISO8601 comes in two formats:
* **`PnYnMnDTnHnMnS`** - `P<date>T<time>`

- **`PnYnMnDTnHnMnS`** - `P<date>T<time>`
The `n` is replaced by the value for each of the date and time elements that follow the `n`.
Leading zeros are not required
* **`PnW`** - the week format

- **`PnW`** - the week format

Check out the details on [Wikipedia](https://en.wikipedia.org/wiki/ISO_8601#Durations)
Check out the details on [Wikipedia](https://en.wikipedia.org/wiki/ISO_8601#Durations)

## Install

```
$ npm install iso8601-duration
```sh
npm install iso8601-duration
```

## Usage

Most noteworthy of the interface is the ability to provide a `date` for `toSeconds`-calculations.
Why becomes evident when working with durations that span dates as all months are not equally long.
E.g January of 2016 is **744 hours** compared to the **696 hours** of February 2016.
E.g January of 2016 is **744 hours** compared to the **696 hours** of February 2016.

If a date is not provided for `toSeconds` the timestamp `Date.now()` is used as baseline.
If a date is not provided for `toSeconds` the timestamp `Date.now()` is used as baseline.

### Interface

Expand All @@ -43,11 +47,13 @@ export default {
```

### Example

Simple usage

```js
import {parse, end, toSeconds, pattern} from 'iso8601-duration';
import { parse, end, toSeconds, pattern } from "iso8601-duration";

console.log(parse('P1Y2M4DT20H44M12.67S'));
console.log(parse("P1Y2M4DT20H44M12.67S"));
/* outputs =>
{
years: 1,
Expand All @@ -59,46 +65,43 @@ console.log(parse('P1Y2M4DT20H44M12.67S'));
}
*/

console.log( toSeconds( parse('PT1H30M10.5S') ) );
console.log(toSeconds(parse("PT1H30M10.5S")));
// outputs => 5410.5

console.log ( end( parse('P1D') ) );
console.log(end(parse("P1D")));
// outputs => DateObj 2017-10-04T10:14:50.190Z

```

A more complete usecase / example

```js
import {parse, toSeconds, pattern} from 'iso8601-duration';
import { parse, toSeconds, pattern } from "iso8601-duration";

// convert iso8601 duration-strings to total seconds from some api
const getWithSensibleDurations = someApiEndpoint => {
// return promise, like fetch does
return new Promise(resolve => {
// fetch text
fetch(someApiEndpoint)
.then(res => res.text())
.then(jsonString => {

// create new pattern that matches on surrounding double-quotes
// so we can replace the string with an actual number
const replacePattern = new RegExp(`\\"${pattern.source}\\"`, 'g');
jsonString = jsonString.replace(replacePattern, m => {
return toSeconds(parse(m));
});
// resolve original request with sensible durations in object
resolve( JSON.parse(jsonString) );
});
});
}

const getWithSensibleDurations = (someApiEndpoint) => {
// return promise, like fetch does
return new Promise((resolve) => {
// fetch text
fetch(someApiEndpoint)
.then((res) => res.text())
.then((jsonString) => {
// create new pattern that matches on surrounding double-quotes
// so we can replace the string with an actual number
const replacePattern = new RegExp(`\\"${pattern.source}\\"`, "g");
jsonString = jsonString.replace(replacePattern, (m) => {
return toSeconds(parse(m));
});
// resolve original request with sensible durations in object
resolve(JSON.parse(jsonString));
});
});
};
```


## License

MIT @ https://tolu.mit-license.org/

[travis]: https://travis-ci.org/tolu/ISO8601-duration "travis build status"
[npm]: https://www.npmjs.com/package/iso8601-duration "npm package"
[bundlephobia]: https://img.shields.io/bundlephobia/minzip/iso8601-duration
[bundlephobia]: https://img.shields.io/bundlephobia/minzip/iso8601-duration
23 changes: 0 additions & 23 deletions index.d.ts

This file was deleted.

29 changes: 29 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @description A module for parsing ISO8601 durations
*/
interface Duration {
years?: number;
months?: number;
weeks?: number;
days?: number;
hours?: number;
minutes?: number;
seconds?: number;
}
/**
* The ISO8601 regex for matching / testing durations
*/
export declare const pattern: RegExp;
/** Parse PnYnMnDTnHnMnS format to object */
export declare const parse: (durationString: string) => Duration;
/** Convert ISO8601 duration object to an end Date. */
export declare const end: (durationInput: Duration, startDate?: Date) => Date;
/** Convert ISO8601 duration object to seconds */
export declare const toSeconds: (durationInput: Duration, startDate?: Date) => number;
declare const _default: {
end: (durationInput: Duration, startDate?: Date) => Date;
toSeconds: (durationInput: Duration, startDate?: Date) => number;
pattern: RegExp;
parse: (durationString: string) => Duration;
};
export default _default;
153 changes: 69 additions & 84 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,101 +1,86 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
"use strict";
/**
* @description A module for parsing ISO8601 durations
*/

Object.defineProperty(exports, "__esModule", { value: true });
exports.toSeconds = exports.end = exports.parse = exports.pattern = void 0;
/**
* The pattern used for parsing ISO8601 duration (PnYnMnDTnHnMnS).
* This does not cover the week format PnW.
*/

// PnYnMnDTnHnMnS
var numbers = '\\d+(?:[\\.,]\\d+)?';
var weekPattern = '(' + numbers + 'W)';
var datePattern = '(' + numbers + 'Y)?(' + numbers + 'M)?(' + numbers + 'D)?';
var timePattern = 'T(' + numbers + 'H)?(' + numbers + 'M)?(' + numbers + 'S)?';

var iso8601 = 'P(?:' + weekPattern + '|' + datePattern + '(?:' + timePattern + ')?)';
var objMap = ['weeks', 'years', 'months', 'days', 'hours', 'minutes', 'seconds'];

var numbers = "\\d+(?:[\\.,]\\d+)?";
var weekPattern = "(".concat(numbers, "W)");
var datePattern = "(".concat(numbers, "Y)?(").concat(numbers, "M)?(").concat(numbers, "D)?");
var timePattern = "T(".concat(numbers, "H)?(").concat(numbers, "M)?(").concat(numbers, "S)?");
var iso8601 = "P(?:".concat(weekPattern, "|").concat(datePattern, "(?:").concat(timePattern, ")?)");
var objMap = [
"weeks",
"years",
"months",
"days",
"hours",
"minutes",
"seconds",
];
var defaultDuration = Object.freeze({
years: 0,
months: 0,
weeks: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: 0
years: 0,
months: 0,
weeks: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});

/**
* The ISO8601 regex for matching / testing durations
*/
var pattern = exports.pattern = new RegExp(iso8601);

/** Parse PnYnMnDTnHnMnS format to object
* @param {string} durationString - PnYnMnDTnHnMnS formatted string
* @return {Object} - With a property for each part of the pattern
*/
var parse = exports.parse = function parse(durationString) {
// Slice away first entry in match-array
return durationString.match(pattern).slice(1).reduce(function (prev, next, idx) {
prev[objMap[idx]] = parseFloat(next) || 0;
return prev;
}, {});
exports.pattern = new RegExp(iso8601);
/** Parse PnYnMnDTnHnMnS format to object */
var parse = function (durationString) {
// Slice away first entry in match-array
return durationString
.match(exports.pattern)
.slice(1)
.reduce(function (prev, next, idx) {
prev[objMap[idx]] = parseFloat(next) || 0;
return prev;
}, {});
};

/**
* Convert ISO8601 duration object to an end Date.
*
* @param {Object} duration - The duration object
* @param {Date} startDate - The starting Date for calculating the duration
* @return {Date} - The resulting end Date
*/
var end = exports.end = function end(duration, startDate) {
duration = Object.assign({}, defaultDuration, duration);

// Create two equal timestamps, add duration to 'then' and return time difference
var timestamp = startDate ? startDate.getTime() : Date.now();
var then = new Date(timestamp);

then.setFullYear(then.getFullYear() + duration.years);
then.setMonth(then.getMonth() + duration.months);
then.setDate(then.getDate() + duration.days);
then.setHours(then.getHours() + duration.hours);
then.setMinutes(then.getMinutes() + duration.minutes);
// Then.setSeconds(then.getSeconds() + duration.seconds);
then.setMilliseconds(then.getMilliseconds() + duration.seconds * 1000);
// Special case weeks
then.setDate(then.getDate() + duration.weeks * 7);

return then;
exports.parse = parse;
/** Convert ISO8601 duration object to an end Date. */
var end = function (durationInput, startDate) {
if (startDate === void 0) { startDate = new Date(); }
var duration = Object.assign({}, defaultDuration, durationInput);
// Create two equal timestamps, add duration to 'then' and return time difference
var timestamp = startDate.getTime();
var then = new Date(timestamp);
then.setFullYear(then.getFullYear() + duration.years);
then.setMonth(then.getMonth() + duration.months);
then.setDate(then.getDate() + duration.days);
then.setHours(then.getHours() + duration.hours);
then.setMinutes(then.getMinutes() + duration.minutes);
// Then.setSeconds(then.getSeconds() + duration.seconds);
then.setMilliseconds(then.getMilliseconds() + duration.seconds * 1000);
// Special case weeks
then.setDate(then.getDate() + duration.weeks * 7);
return then;
};

/**
* Convert ISO8601 duration object to seconds
*
* @param {Object} duration - The duration object
* @param {Date} startDate - The starting point for calculating the duration
* @return {Number}
*/
var toSeconds = exports.toSeconds = function toSeconds(duration, startDate) {
duration = Object.assign({}, defaultDuration, duration);

var timestamp = startDate ? startDate.getTime() : Date.now();
var now = new Date(timestamp);
var then = end(duration, now);

var seconds = (then.getTime() - now.getTime()) / 1000;
return seconds;
exports.end = end;
/** Convert ISO8601 duration object to seconds */
var toSeconds = function (durationInput, startDate) {
if (startDate === void 0) { startDate = new Date(); }
var duration = Object.assign({}, defaultDuration, durationInput);
var timestamp = startDate.getTime();
var now = new Date(timestamp);
var then = (0, exports.end)(duration, now);
var seconds = (then.getTime() - now.getTime()) / 1000;
return seconds;
};

exports.toSeconds = toSeconds;
exports.default = {
end: end,
toSeconds: toSeconds,
pattern: pattern,
parse: parse
};
end: exports.end,
toSeconds: exports.toSeconds,
pattern: exports.pattern,
parse: exports.parse,
};
Loading

0 comments on commit daa03c9

Please sign in to comment.