Skip to content

Commit

Permalink
feat: change factory interface
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `d(1).second` should be changed to `d(1, "second")`
  • Loading branch information
BDav24 committed Apr 7, 2023
1 parent 877cb80 commit bf4d90c
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 263 deletions.
151 changes: 56 additions & 95 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Syntactic sugar functions to handle duration and dates.

```javascript
const duration = d(2).days.plus(d(1).hour)
const duration = d(2, "days").plus(d(1, "hour"))

duration.inMinutes
// 2940
Expand Down Expand Up @@ -38,15 +38,13 @@ npm install x-duration
```javascript
import d from "x-duration"

const duration = d(2).minutes
const duration = d(2, "minutes")

// setTimeout(..., duration.inMs)
```

## Documentation

This library manipulates 2 kinds of objects: `XDurationFactory` and `XDuration`.

```javascript
import d, { XDurationFactory, XDuration } from "x-duration"
```
Expand All @@ -55,94 +53,57 @@ import d, { XDurationFactory, XDuration } from "x-duration"

```javascript
declare const d: {
// Returns a factory to create durations
(value: number): XDurationFactory;
// Factory to create durations
(value: number, unit: XDurationUnitInput): XDuration;

// Re-wrap a duration (in milliseconds) after summing them
sum(value: number): XDuration;
};

declare class XDurationFactory {
constructor(value: number);

// Returns a duration in milliseconds
get milliseconds(): XDuration;
// Alias of `milliseconds`
get millisecond(): XDuration;

// Returns a duration in seconds
get seconds(): XDuration;
// Alias of `seconds`
get second(): XDuration;

// Returns a duration in minutes
get minutes(): XDuration;
// Alias of `minutes`
get minute(): XDuration;

// Returns a duration in hour
get hour(): XDuration;
// Alias of `hour`
get hours(): XDuration;

// Returns a duration in days
get days(): XDuration;
// Alias of `days`
get day(): XDuration;

// Returns a duration in weeks
get weeks(): XDuration;
// Alias of `weeks`
get week(): XDuration;

// Returns a duration in months
get months(): XDuration;
// Alias of `months`
get month(): XDuration;

// Returns a duration in quarters
get quarters(): XDuration;
// Alias of `quarters`
get quarter(): XDuration;

// Returns a duration in years
get years(): XDuration;
// Alias of `years`
get year(): XDuration;
}
type XDurationUnitInput =
| "milliseconds" | "millisecond" | "ms"
| "seconds" | "second" | "s"
| "minutes" | "minute" | "m"
| "hours" | "hour" | "h"
| "days" | "day" | "D"
| "weeks" | "week" | "W"
| "months" | "month" | "M"
| "quarters" | "quarter" | "Q"
| "years" | "year" | "Y";
```

#### Examples

```javascript
d(10).milliseconds
d(1).millisecond
d(10, "milliseconds")
d(1, "millisecond")

d(10).seconds
d(1).second
d(10, "seconds")
d(1, "second")

d(10).minutes
d(1).minute
d(10, "minutes")
d(1, "minute")

d(10).hours
d(1).hour
d(10, "hours")
d(1, "hour")

d(10).days
d(1).day
d(10, "days")
d(1, "day")

d(10).weeks
d(1).week
d(10, "weeks")
d(1, "week")

d(10).months
d(1).month
d(10, "months")
d(1, "month")

d(10).quarters
d(1).quarter
d(10, "quarters")
d(1, "quarter")

d(10).years
d(1).year
d(10, "years")
d(1, "year")

d.sum(d(1).hour + d(10).minutes)
d.sum(d(1, "hour") + d(10, "minutes"))
d.sum(d(1, "hour") - d(10, "minutes"))
```

### XDuration
Expand Down Expand Up @@ -232,48 +193,48 @@ declare class XDuration {
/**
* Unit converters
*/
d(86400000).millisecond.inDays
d(86400000, "millisecond").inDays
// 1

d(30).seconds.inMilliseconds
d(30, "seconds").inMilliseconds
// 30000

d(1).minute.inMilliseconds
d(1, "minute").inMilliseconds
// 60000

d(10).minutes.inSeconds
d(10, "minutes").inSeconds
// 600

d(1.5).hours.inMinutes
d(1.5, "hours").inMinutes
// 90

d(1.5).days.inHours
d(1.5, "days").inHours
// 36

d(0.5).weeks.inHours
d(0.5, "weeks").inHours
// 84 (3 * 24 + 12)

d(0.5).months.inDays
d(0.5, "months").inDays
// 15

d(1.5).quarters.inMonths
d(1.5, "quarters").inMonths
// 4.5

d(1.5).years.inMonths
d(1.5, "years").inMonths
// 18
```

```javascript
/**
* Transformations
*/
d(2).hours.plus(d(90).minutes).toObject()
d(2, "hours").plus(d(90, "minutes")).toObject()
// { hours: 2, minutes: 90 }

d(2).hours.minus(d(90).minutes).toObject()
d(2, "hours").minus(d(90, "minutes")).toObject()
// { hours: 2, minutes: -90 }

d(2).hours.plus(d(90).minutes).rescale().toObject()
d(2, "hours").plus(d(90, "minutes")).rescale().toObject()
// { hours: 3, minutes: 30 }
```

Expand All @@ -283,24 +244,24 @@ d(2).hours.plus(d(90).minutes).rescale().toObject()
*/
// Let's say the current date is "2036-01-01 12:00:00 GMT"

d(3).minutes.ago
d(3, "minutes").ago
// 2036-01-01T11:57:00.000Z

d(2).hours.fromNow
d(2, "hours").fromNow
// 2036-01-01T14:00:00.000Z

d(2).hours.before(new Date("2036-01-01 12:00:00 GMT"))
d(2, "hours").before(new Date("2036-01-01 12:00:00 GMT"))
// 2036-01-01T10:00:00.000Z

d(3).minutes.after(new Date("2036-01-01 12:00:00 GMT"))
d(3, "minutes").after(new Date("2036-01-01 12:00:00 GMT"))
// 2036-01-01T12:03:00.000Z
```

```javascript
/**
* Outputs
*/
const duration = d(2).months.plus(d(10).days).plus(d(1).minute)
const duration = d(2, "months").plus(d(10, "days")).plus(d(1, "minute"))

duration.valueOf()
// 6048060000
Expand All @@ -320,14 +281,14 @@ duration.toObject()
Operator overloading is not really possible in Javascript, but you can sum durations to other durations (though it has some limitations, and typescript is not really happy about it.)

```javascript
d(2).hours + d(1).minute
d(2, "hours") + d(1, "minute")
// 7260000 (duration in milliseconds), so we can re-wrap it as a duration:

d.sum(d(2).hours + d(1).minute).toObject()
d.sum(d(2, "hours") + d(1, "minute")).toObject()
// { hours: 2, minutes: 1 }
```

```javascript
setTimeout(..., d(1).minute)
// will work but it's better calling explicitly "setTimeout(..., d(1).minute.inMs)"
setTimeout(..., d(1, "minute"))
// will work but it's better calling explicitly "setTimeout(..., d(1, "minute").inMs)"
```
45 changes: 24 additions & 21 deletions src/__tests__/demo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,55 @@ import d, { XDuration } from "../index";

describe("Basic usage", () => {
test("It makes duration unit convertion more expressive", () => {
expect(d(86400000).millisecond.inDays).toBe(1);
expect(d(30).seconds.inMilliseconds).toBe(30000);
expect(d(1).minute.inMilliseconds).toBe(60000);
expect(d(10).minutes.inSeconds).toBe(600);
expect(d(1.5).hours.inMinutes).toBe(90);
expect(d(1.5).days.inHours).toBe(36);
expect(d(0.5).weeks.inHours).toBe(3 * 24 + 12);
expect(d(0.5).months.inDays).toBe(15);
expect(d(1.5).quarters.inMonths).toBe(4.5);
expect(d(1.5).years.inMonths).toBe(18);
expect(d(86400000, "milliseconds").inDays).toBe(1);
expect(d(30, "seconds").inMilliseconds).toBe(30000);
expect(d(1, "minute").inMilliseconds).toBe(60000);
expect(d(10, "minutes").inSeconds).toBe(600);
expect(d(1.5, "hours").inMinutes).toBe(90);
expect(d(1.5, "days").inHours).toBe(36);
expect(d(0.5, "weeks").inHours).toBe(3 * 24 + 12);
expect(d(0.5, "months").inDays).toBe(15);
expect(d(1.5, "quarters").inMonths).toBe(4.5);
expect(d(1.5, "years").inMonths).toBe(18);
});

test("It helps manipulating dates", () => {
const nowSeconds = Date.now() / 1000;

expect(d(3).minutes.ago.getTime() / 1000).toBeCloseTo(nowSeconds - 180, 1);
expect(d(2).hours.fromNow.getTime() / 1000).toBeCloseTo(
expect(d(3, "minutes").ago.getTime() / 1000).toBeCloseTo(
nowSeconds - 180,
1
);
expect(d(2, "hours").fromNow.getTime() / 1000).toBeCloseTo(
nowSeconds + 7200,
1
);

const givenDate = new Date("2036-01-01 12:00:00");
const givenDateSeconds = givenDate.getTime() / 1000;
expect(d(2).hours.before(givenDate).getTime() / 1000).toBeCloseTo(
expect(d(2, "hours").before(givenDate).getTime() / 1000).toBeCloseTo(
givenDateSeconds - 7200,
1
);
expect(d(3).minutes.after(givenDate).getTime() / 1000).toBeCloseTo(
expect(d(3, "minutes").after(givenDate).getTime() / 1000).toBeCloseTo(
givenDateSeconds + 180,
1
);
});

test("It helps manipulating durations", () => {
expect(d(2).hours.plus(d(1).minute).toISO()).toBe("PT2H1M");
expect(d(2).hours.minus(d(1).minute).toISO()).toBe("PT2H-1M");
expect(d(2, "hours").plus(d(1, "minute")).toISO()).toBe("PT2H1M");
expect(d(2, "hours").minus(d(1, "minute")).toISO()).toBe("PT2H-1M");

// Rescales units to their largest representation
expect(d(90).minutes.rescale().toObject()).toStrictEqual({
expect(d(90, "minutes").rescale().toObject()).toStrictEqual({
hours: 1,
minutes: 30,
});
});

test("It helps to output durations", () => {
const duration = d(2).months.plus(d(10).days).plus(d(1).minute);
const duration = d(2, "months").plus(d(10, "days")).plus(d(1, "minute"));

expect(duration.toISO()).toBe("P2M10DT1M");
expect(duration.toFormat("M S")).toBe("2 864060000");
Expand All @@ -72,7 +75,7 @@ describe("Fixes JS Date shortcomings", () => {
);

// With Luxon
expect(d(1).month.after(new Date("2036-01-31")).toISOString()).toBe(
expect(d(1, "month").after(new Date("2036-01-31")).toISOString()).toBe(
new Date("2036-02-29").toISOString()
);
});
Expand All @@ -87,7 +90,7 @@ describe("Type unboxing", () => {
test("XDuration + XDuration", () => {
// @ts-ignore: The right-hand side of an arithmetic operation must be of type
// 'any', 'number', 'bigint' or an enum type
expect(d.sum(d(2).hours - d(1).minute).toISO()).toBe("PT1H59M");
expect(d.sum(d(2, "hours") - d(1, "minute")).toISO()).toBe("PT1H59M");

// Note: XDuration + XDuration will return a number (duration in milliseconds),
// so we need to re-wrap it with "d.sum" (and result might differ from calling
Expand All @@ -99,7 +102,7 @@ describe("Type unboxing", () => {
const callback = jest.fn();

// @ts-ignore: Argument of type 'XDuration' is not assignable to parameter of type 'number'
setTimeout(callback, d(1).minute);
setTimeout(callback, d(1, "minute"));

// Note: you can also call: setTimeout(callback, d(1).minute.inMs)

Expand Down

0 comments on commit bf4d90c

Please sign in to comment.