@sjts/lib-date 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +9 -0
- package/LICENCE +5 -0
- package/dist/DateConsts.d.ts +3 -0
- package/dist/DateConsts.js +3 -0
- package/dist/DateRange.d.ts +6 -0
- package/dist/DateRange.js +1 -0
- package/dist/Duration.d.ts +6 -0
- package/dist/Duration.js +1 -0
- package/dist/DurationUnit.d.ts +9 -0
- package/dist/DurationUnit.js +10 -0
- package/dist/Tense.d.ts +6 -0
- package/dist/Tense.js +7 -0
- package/dist/TimeFrame.d.ts +7 -0
- package/dist/TimeFrame.js +1 -0
- package/dist/addDuration.d.ts +4 -0
- package/dist/addDuration.js +21 -0
- package/dist/calcDateRangeDiff.d.ts +3 -0
- package/dist/calcDateRangeDiff.js +4 -0
- package/dist/calcDateRangeDiff.test.d.ts +1 -0
- package/dist/calcDateRangeDiff.test.js +23 -0
- package/dist/calcDateRangeGaps.d.ts +3 -0
- package/dist/calcDateRangeGaps.js +25 -0
- package/dist/calcDateRangeOverlap.d.ts +3 -0
- package/dist/calcDateRangeOverlap.js +16 -0
- package/dist/calcDateRangeOverlap.test.d.ts +1 -0
- package/dist/calcDateRangeOverlap.test.js +63 -0
- package/dist/dateRange2Tense.d.ts +4 -0
- package/dist/dateRange2Tense.js +11 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +18 -0
- package/dist/isDateWithinRange.d.ts +4 -0
- package/dist/isDateWithinRange.js +6 -0
- package/dist/logDateRange.d.ts +3 -0
- package/dist/logDateRange.js +4 -0
- package/dist/logTimeFrame.d.ts +3 -0
- package/dist/logTimeFrame.js +4 -0
- package/dist/mergeDateRanges.d.ts +3 -0
- package/dist/mergeDateRanges.js +14 -0
- package/dist/newDateFromISO.d.ts +3 -0
- package/dist/newDateFromISO.js +5 -0
- package/dist/newDateFromJS.d.ts +3 -0
- package/dist/newDateFromJS.js +5 -0
- package/dist/newDateFromMillis.d.ts +3 -0
- package/dist/newDateFromMillis.js +5 -0
- package/dist/noOfWeekdays.d.ts +3 -0
- package/dist/noOfWeekdays.js +16 -0
- package/dist/timeFrame2DateRange.d.ts +4 -0
- package/dist/timeFrame2DateRange.js +14 -0
- package/dist/timeFrame2Tense.d.ts +4 -0
- package/dist/timeFrame2Tense.js +6 -0
- package/package.json +25 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
extends: [require.resolve('@sjts/lib-dev/eslintrc.base')],
|
|
3
|
+
ignorePatterns: ['*.d.ts', 'admin/*', '*.test.ts', '*/node_modules/*', '*.js'],
|
|
4
|
+
parserOptions: {
|
|
5
|
+
project: 'tsconfig.json',
|
|
6
|
+
tsconfigRootDir: __dirname,
|
|
7
|
+
createDefaultProgram: true,
|
|
8
|
+
},
|
|
9
|
+
}
|
package/LICENCE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/Duration.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export var DurationUnit;
|
|
2
|
+
(function (DurationUnit) {
|
|
3
|
+
DurationUnit["DAY"] = "day";
|
|
4
|
+
DurationUnit["WEEK"] = "week";
|
|
5
|
+
DurationUnit["FORTNIGHT"] = "fortnight";
|
|
6
|
+
DurationUnit["MONTH"] = "month";
|
|
7
|
+
DurationUnit["QUARTER"] = "quarter";
|
|
8
|
+
DurationUnit["YEAR"] = "year";
|
|
9
|
+
})(DurationUnit || (DurationUnit = {}));
|
|
10
|
+
export default DurationUnit;
|
package/dist/Tense.d.ts
ADDED
package/dist/Tense.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import DurationUnit from './DurationUnit.js';
|
|
2
|
+
export function addDuration(date, duration) {
|
|
3
|
+
if (!duration)
|
|
4
|
+
return date;
|
|
5
|
+
const { unit, count = 1 } = duration;
|
|
6
|
+
switch (unit) {
|
|
7
|
+
case DurationUnit.DAY:
|
|
8
|
+
return date.plus({ day: count });
|
|
9
|
+
case DurationUnit.WEEK:
|
|
10
|
+
return date.plus({ day: count * 7 });
|
|
11
|
+
case DurationUnit.FORTNIGHT:
|
|
12
|
+
return date.plus({ day: count * 14 });
|
|
13
|
+
case DurationUnit.MONTH:
|
|
14
|
+
return date.plus({ month: count });
|
|
15
|
+
case DurationUnit.QUARTER:
|
|
16
|
+
return date.plus({ month: count * 3 });
|
|
17
|
+
case DurationUnit.YEAR:
|
|
18
|
+
return date.plus({ year: count });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export default addDuration;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { unitTest } from '@sjts/lib-dev';
|
|
2
|
+
import calcDateRangeDiff from './calcDateRangeDiff';
|
|
3
|
+
import newDateFromISO from './newDateFromISO';
|
|
4
|
+
const file = 'File';
|
|
5
|
+
const arg = 'Arg';
|
|
6
|
+
describe('calcDateRangeOverlap', () => {
|
|
7
|
+
unitTest('good - month', async () => {
|
|
8
|
+
const t = {
|
|
9
|
+
startDate: newDateFromISO('2000-01-01'),
|
|
10
|
+
endDate: newDateFromISO('2000-02-01'),
|
|
11
|
+
};
|
|
12
|
+
const r = calcDateRangeDiff(t);
|
|
13
|
+
expect(r).toBe(31);
|
|
14
|
+
});
|
|
15
|
+
unitTest('good - 2 days', async () => {
|
|
16
|
+
const t = {
|
|
17
|
+
startDate: newDateFromISO('2000-01-01'),
|
|
18
|
+
endDate: newDateFromISO('2000-01-03'),
|
|
19
|
+
};
|
|
20
|
+
const r = calcDateRangeDiff(t);
|
|
21
|
+
expect(r).toBe(2);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { sortBy } from 'lodash-es';
|
|
2
|
+
export default calcDateRangeGaps;
|
|
3
|
+
export function calcDateRangeGaps(outerRange, innerRanges) {
|
|
4
|
+
// Filter innerRanges to just include ranges that are within the outer range
|
|
5
|
+
// And sort them by their reverse start date (so we can POP the earliest)
|
|
6
|
+
const validInnerRanges = sortBy(innerRanges.filter(({ startDate, endDate }) => startDate < outerRange.endDate || endDate >= outerRange.startDate), ({ startDate }) => startDate.toMillis()).reverse();
|
|
7
|
+
// If there are no valid inner ranges, the entire outerRange is a "gap"
|
|
8
|
+
if (!validInnerRanges?.length)
|
|
9
|
+
return [outerRange];
|
|
10
|
+
// Build up an array of gaps
|
|
11
|
+
const results = [];
|
|
12
|
+
// Loop through all start dates, filling in gaps if necessary
|
|
13
|
+
let currentStartDate = outerRange.startDate;
|
|
14
|
+
while (!!validInnerRanges.length) {
|
|
15
|
+
const innerRange = validInnerRanges.pop();
|
|
16
|
+
// If our start date is before the innerRange start date, we have a gap
|
|
17
|
+
if (currentStartDate < innerRange.startDate && currentStartDate < innerRange.endDate)
|
|
18
|
+
results.push({ startDate: currentStartDate, endDate: innerRange.startDate });
|
|
19
|
+
// Our new start date is the end of the innerRange
|
|
20
|
+
currentStartDate = innerRange.endDate;
|
|
21
|
+
}
|
|
22
|
+
if (!outerRange.endDate || currentStartDate < outerRange.endDate)
|
|
23
|
+
results.push({ startDate: currentStartDate, endDate: outerRange.endDate });
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default calcDateRangeOverlap;
|
|
2
|
+
export function calcDateRangeOverlap(base, over) {
|
|
3
|
+
const oS = over.startDate;
|
|
4
|
+
const oE = over.endDate;
|
|
5
|
+
const bS = base.startDate;
|
|
6
|
+
const bE = base.endDate;
|
|
7
|
+
if (oS > bE)
|
|
8
|
+
return undefined;
|
|
9
|
+
if (oE < bS)
|
|
10
|
+
return undefined;
|
|
11
|
+
// prettier-ignore
|
|
12
|
+
const startDate = (!oS && !!bS) || (oS < bS) ? bS : oS;
|
|
13
|
+
// prettier-ignore
|
|
14
|
+
const endDate = (!bE && !!oE) || (oE < bE) ? oE : bE;
|
|
15
|
+
return { startDate, endDate };
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { unitTest } from '@sjts/lib-dev';
|
|
2
|
+
import calcDateRangeOverlap from './calcDateRangeOverlap';
|
|
3
|
+
import newDateFromISO from './newDateFromISO';
|
|
4
|
+
const file = 'File';
|
|
5
|
+
const arg = 'Arg';
|
|
6
|
+
describe('calcDateRangeOverlap', () => {
|
|
7
|
+
const testRange = {
|
|
8
|
+
startDate: newDateFromISO('2000-01-01'),
|
|
9
|
+
endDate: newDateFromISO('2000-02-01'),
|
|
10
|
+
};
|
|
11
|
+
unitTest('good - fully inside', async () => {
|
|
12
|
+
const t = {
|
|
13
|
+
startDate: newDateFromISO('2000-01-10'),
|
|
14
|
+
endDate: newDateFromISO('2000-01-12'),
|
|
15
|
+
};
|
|
16
|
+
const r = calcDateRangeOverlap(testRange, t);
|
|
17
|
+
expect(r?.startDate === t.startDate).toBeTruthy();
|
|
18
|
+
expect(r?.endDate === t.endDate).toBeTruthy();
|
|
19
|
+
});
|
|
20
|
+
unitTest('good - fully outside after', async () => {
|
|
21
|
+
const t = {
|
|
22
|
+
startDate: newDateFromISO('2000-03-01'),
|
|
23
|
+
endDate: newDateFromISO('2000-03-10'),
|
|
24
|
+
};
|
|
25
|
+
const r = calcDateRangeOverlap(testRange, t);
|
|
26
|
+
expect(r).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
unitTest('good - fully outside before', async () => {
|
|
29
|
+
const t = {
|
|
30
|
+
startDate: newDateFromISO('1999-03-01'),
|
|
31
|
+
endDate: newDateFromISO('1999-03-10'),
|
|
32
|
+
};
|
|
33
|
+
const r = calcDateRangeOverlap(testRange, t);
|
|
34
|
+
expect(r).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
unitTest('good - fully overlap', async () => {
|
|
37
|
+
const t = {
|
|
38
|
+
startDate: newDateFromISO('1999-03-01'),
|
|
39
|
+
endDate: newDateFromISO('2003-03-10'),
|
|
40
|
+
};
|
|
41
|
+
const r = calcDateRangeOverlap(testRange, t);
|
|
42
|
+
expect(r?.startDate === testRange.startDate).toBeTruthy();
|
|
43
|
+
expect(r?.endDate === testRange.endDate).toBeTruthy();
|
|
44
|
+
});
|
|
45
|
+
unitTest('good - part overlap - before', async () => {
|
|
46
|
+
const t = {
|
|
47
|
+
startDate: newDateFromISO('1999-03-01'),
|
|
48
|
+
endDate: newDateFromISO('2000-01-10'),
|
|
49
|
+
};
|
|
50
|
+
const r = calcDateRangeOverlap(testRange, t);
|
|
51
|
+
expect(r?.startDate === testRange.startDate).toBeTruthy();
|
|
52
|
+
expect(r?.endDate === t.endDate).toBeTruthy();
|
|
53
|
+
});
|
|
54
|
+
unitTest('good - part overlap - after', async () => {
|
|
55
|
+
const t = {
|
|
56
|
+
startDate: newDateFromISO('2000-01-10'),
|
|
57
|
+
endDate: newDateFromISO('2000-03-10'),
|
|
58
|
+
};
|
|
59
|
+
const r = calcDateRangeOverlap(testRange, t);
|
|
60
|
+
expect(r?.startDate === t.startDate).toBeTruthy();
|
|
61
|
+
expect(r?.endDate === testRange.endDate).toBeTruthy();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
import Tense from './Tense.js';
|
|
3
|
+
export default dateRange2Tense;
|
|
4
|
+
export function dateRange2Tense(dateRange) {
|
|
5
|
+
const now = DateTime.now().startOf('day');
|
|
6
|
+
if (dateRange?.startDate > now)
|
|
7
|
+
return Tense.FUTURE;
|
|
8
|
+
if (dateRange?.endDate < now)
|
|
9
|
+
return Tense.PAST;
|
|
10
|
+
return Tense.PRESENT;
|
|
11
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export * from './DateConsts.js';
|
|
2
|
+
export { DateRange } from './DateRange.js';
|
|
3
|
+
export { Duration } from './Duration.js';
|
|
4
|
+
export { DurationUnit } from './DurationUnit.js';
|
|
5
|
+
export { Tense } from './Tense.js';
|
|
6
|
+
export { TimeFrame } from './TimeFrame.js';
|
|
7
|
+
export { addDuration } from './addDuration.js';
|
|
8
|
+
export { calcDateRangeDiff } from './calcDateRangeDiff.js';
|
|
9
|
+
export { calcDateRangeGaps } from './calcDateRangeGaps.js';
|
|
10
|
+
export { calcDateRangeOverlap } from './calcDateRangeOverlap.js';
|
|
11
|
+
export { dateRange2Tense } from './dateRange2Tense.js';
|
|
12
|
+
export { isDateWithinRange } from './isDateWithinRange.js';
|
|
13
|
+
export { logDateRange } from './logDateRange.js';
|
|
14
|
+
export { logTimeFrame } from './logTimeFrame.js';
|
|
15
|
+
export { mergeDateRanges } from './mergeDateRanges.js';
|
|
16
|
+
export { newDateFromISO } from './newDateFromISO.js';
|
|
17
|
+
export { newDateFromJS } from './newDateFromJS.js';
|
|
18
|
+
export { newDateFromMillis } from './newDateFromMillis.js';
|
|
19
|
+
export { noOfWeekdays } from './noOfWeekdays.js';
|
|
20
|
+
export { timeFrame2DateRange } from './timeFrame2DateRange.js';
|
|
21
|
+
export { timeFrame2Tense } from './timeFrame2Tense.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export * from './DateConsts.js';
|
|
2
|
+
export { DurationUnit } from './DurationUnit.js';
|
|
3
|
+
export { Tense } from './Tense.js';
|
|
4
|
+
export { addDuration } from './addDuration.js';
|
|
5
|
+
export { calcDateRangeDiff } from './calcDateRangeDiff.js';
|
|
6
|
+
export { calcDateRangeGaps } from './calcDateRangeGaps.js';
|
|
7
|
+
export { calcDateRangeOverlap } from './calcDateRangeOverlap.js';
|
|
8
|
+
export { dateRange2Tense } from './dateRange2Tense.js';
|
|
9
|
+
export { isDateWithinRange } from './isDateWithinRange.js';
|
|
10
|
+
export { logDateRange } from './logDateRange.js';
|
|
11
|
+
export { logTimeFrame } from './logTimeFrame.js';
|
|
12
|
+
export { mergeDateRanges } from './mergeDateRanges.js';
|
|
13
|
+
export { newDateFromISO } from './newDateFromISO.js';
|
|
14
|
+
export { newDateFromJS } from './newDateFromJS.js';
|
|
15
|
+
export { newDateFromMillis } from './newDateFromMillis.js';
|
|
16
|
+
export { noOfWeekdays } from './noOfWeekdays.js';
|
|
17
|
+
export { timeFrame2DateRange } from './timeFrame2DateRange.js';
|
|
18
|
+
export { timeFrame2Tense } from './timeFrame2Tense.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default mergeDateRanges;
|
|
2
|
+
export function mergeDateRanges(dateRanges) {
|
|
3
|
+
let startDate;
|
|
4
|
+
let endDate;
|
|
5
|
+
dateRanges.forEach(d => {
|
|
6
|
+
if (!d)
|
|
7
|
+
return;
|
|
8
|
+
if (!!d.startDate && (!startDate || d.startDate < startDate))
|
|
9
|
+
startDate = d.startDate;
|
|
10
|
+
if (!!d.endDate && (!endDate || d.endDate < endDate))
|
|
11
|
+
endDate = d.endDate;
|
|
12
|
+
});
|
|
13
|
+
return !!startDate || !!endDate ? { startDate, endDate } : undefined;
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default noOfWeekdays;
|
|
2
|
+
export function noOfWeekdays(dateRange) {
|
|
3
|
+
if (!dateRange)
|
|
4
|
+
return undefined;
|
|
5
|
+
const { startDate, endDate } = dateRange;
|
|
6
|
+
if (!startDate || !endDate)
|
|
7
|
+
return undefined;
|
|
8
|
+
let count = 0;
|
|
9
|
+
let currentDate = startDate;
|
|
10
|
+
while (currentDate <= endDate) {
|
|
11
|
+
if (currentDate.weekday < 6)
|
|
12
|
+
count++;
|
|
13
|
+
currentDate = currentDate.plus({ day: 1 });
|
|
14
|
+
}
|
|
15
|
+
return count;
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import addDuration from './addDuration.js';
|
|
2
|
+
export default timeFrame2DateRange;
|
|
3
|
+
// NOTE: Time frames and addDuration are subtly DIFFERENT
|
|
4
|
+
//
|
|
5
|
+
// 1st October ADD 1 month is 1st November (addDuration)
|
|
6
|
+
// The timeframe starting on 1st October and lasting 1 month ... ends on 31st of October
|
|
7
|
+
export function timeFrame2DateRange(timeFrame) {
|
|
8
|
+
return {
|
|
9
|
+
startDate: timeFrame?.startDate?.startOf('day') ?? undefined,
|
|
10
|
+
endDate: addDuration(timeFrame?.startDate, timeFrame?.duration)
|
|
11
|
+
?.startOf('day')
|
|
12
|
+
.minus({ day: 1 }),
|
|
13
|
+
};
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sjts/lib-date",
|
|
3
|
+
"description": "The Steve James Typescript date utils package",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"lodash-es": "4.17.21",
|
|
17
|
+
"luxon": "3.1.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@sjts/lib-dev": "1.1.0"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
}
|
|
25
|
+
}
|