@alanszp/relative-date 16.4.3 → 16.5.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.
Files changed (43) hide show
  1. package/README.md +168 -0
  2. package/dist/DateExpression.d.ts +74 -0
  3. package/dist/DateExpression.js +124 -0
  4. package/dist/DateExpression.js.map +1 -0
  5. package/dist/DateExpression.test.d.ts +1 -0
  6. package/dist/DateExpression.test.js +495 -0
  7. package/dist/DateExpression.test.js.map +1 -0
  8. package/dist/Modifier.d.ts +26 -0
  9. package/dist/Modifier.js +84 -0
  10. package/dist/Modifier.js.map +1 -0
  11. package/dist/Modifier.test.d.ts +1 -0
  12. package/dist/Modifier.test.js +430 -0
  13. package/dist/Modifier.test.js.map +1 -0
  14. package/dist/date-parser/AbsoluteDateParser.d.ts +5 -0
  15. package/dist/date-parser/AbsoluteDateParser.js +15 -0
  16. package/dist/date-parser/AbsoluteDateParser.js.map +1 -0
  17. package/dist/date-parser/DateParser.d.ts +4 -0
  18. package/dist/date-parser/DateParser.js +3 -0
  19. package/dist/date-parser/DateParser.js.map +1 -0
  20. package/dist/date-parser/DateParserFactory.d.ts +4 -0
  21. package/dist/date-parser/DateParserFactory.js +19 -0
  22. package/dist/date-parser/DateParserFactory.js.map +1 -0
  23. package/dist/date-parser/RelativeDateParser.d.ts +26 -0
  24. package/dist/date-parser/RelativeDateParser.js +101 -0
  25. package/dist/date-parser/RelativeDateParser.js.map +1 -0
  26. package/dist/date-parser/RelativeDateParser.test.d.ts +1 -0
  27. package/dist/date-parser/RelativeDateParser.test.js +351 -0
  28. package/dist/date-parser/RelativeDateParser.test.js.map +1 -0
  29. package/dist/errors/InvalidDateExpression.d.ts +3 -0
  30. package/dist/errors/InvalidDateExpression.js +10 -0
  31. package/dist/errors/InvalidDateExpression.js.map +1 -0
  32. package/dist/errors/InvalidModifier.d.ts +3 -0
  33. package/dist/errors/InvalidModifier.js +10 -0
  34. package/dist/errors/InvalidModifier.js.map +1 -0
  35. package/dist/index.d.ts +5 -0
  36. package/dist/index.js +11 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/relativeDateToFixed.d.ts +0 -2
  39. package/dist/relativeDateToFixed.js +7 -107
  40. package/dist/relativeDateToFixed.js.map +1 -1
  41. package/dist/relativeDateToFixed.test.js +0 -258
  42. package/dist/relativeDateToFixed.test.js.map +1 -1
  43. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # Relative Date
2
+
3
+ ## Date Expressions
4
+
5
+ A date expression encapsulates the logic for absolute and relative date. They may contain an optional modifier
6
+
7
+ ### Modifiers
8
+
9
+ Modifiers allow you to adjust a date to the beginning or end of a specific time period. They are appended to date expressions using a colon (`:`) separator.
10
+
11
+ #### Syntax
12
+
13
+ ```
14
+ <date_expression>:<modifier>
15
+ ```
16
+
17
+ Where:
18
+
19
+ - `<date_expression>` is any valid date (absolute, relative, or "now")
20
+ - `<modifier>` follows the pattern `[se]o[unit]`
21
+ - `s` = start of
22
+ - `e` = end of
23
+ - `o` = literal "o"
24
+ - `[unit]` = time unit (see below)
25
+
26
+ #### Available Time Units
27
+
28
+ | Unit | Description | Example |
29
+ | ---- | ------------------- | ------------------------- |
30
+ | `y` | Year | `eoy` = end of year |
31
+ | `s` | Semester (6 months) | `sos` = start of semester |
32
+ | `t` | Third (4 months) | `sot` = start of third |
33
+ | `q` | Quarter (3 months) | `soq` = start of quarter |
34
+ | `b` | Bimester (2 months) | `eob` = end of bimester |
35
+ | `m` | Month | `eom` = end of month |
36
+ | `w` | Week | `som` = start of month |
37
+
38
+ #### Examples
39
+
40
+ **Basic Usage:**
41
+
42
+ ```javascript
43
+ // Start of month
44
+ DateExpression.from("2023-06-15:som"); // Returns 2023-06-01
45
+ DateExpression.from("now:som"); // Returns start of current month
46
+
47
+ // End of month
48
+ DateExpression.from("2023-06-15:eom"); // Returns 2023-06-30
49
+ DateExpression.from("now:eom"); // Returns end of current month
50
+
51
+ // Start of year
52
+ DateExpression.from("2023-06-15:soy"); // Returns 2023-01-01
53
+ DateExpression.from("now:soy"); // Returns start of current year
54
+
55
+ // End of year
56
+ DateExpression.from("2023-06-15:eoy"); // Returns 2023-12-31
57
+ DateExpression.from("now:eoy"); // Returns end of current year
58
+ ```
59
+
60
+ **With Relative Dates:**
61
+
62
+ ```javascript
63
+ // Start of month for a date 5 days from now
64
+ DateExpression.from("+5d:som"); // Returns start of month for date 5 days from now
65
+
66
+ // End of quarter for a date 2 months ago
67
+ DateExpression.from("-2m:eoq"); // Returns end of quarter for date 2 months ago
68
+
69
+ // Start of year for yesterday
70
+ DateExpression.from("-1d:soy"); // Returns start of year for yesterday
71
+ ```
72
+
73
+ **Advanced Time Periods:**
74
+
75
+ ```javascript
76
+ // Semester (6-month periods: Jan-Jun, Jul-Dec)
77
+ DateExpression.from("2023-04-15:sos"); // Returns 2023-01-01 (start of semester)
78
+ DateExpression.from("2023-08-15:eos"); // Returns 2023-12-31 (end of semester)
79
+
80
+ // Bimester (2-month periods: Jan-Feb, Mar-Apr, etc.)
81
+ DateExpression.from("2023-03-15:sob"); // Returns 2023-03-01 (start of bimester)
82
+ DateExpression.from("2023-05-15:eob"); // Returns 2023-04-30 (end of bimester)
83
+
84
+ // Third (4-month periods: Jan-Apr, May-Aug, Sep-Dec)
85
+ DateExpression.from("2023-06-15:sot"); // Returns 2023-05-01 (start of third)
86
+ DateExpression.from("2023-07-15:eot"); // Returns 2023-08-31 (end of third)
87
+ ```
88
+
89
+ **Week Boundaries:**
90
+
91
+ ```javascript
92
+ // Start of week (Sunday by default)
93
+ DateExpression.from("2023-06-15:sow"); // Returns start of week containing June 15
94
+
95
+ // End of week (Saturday by default)
96
+ DateExpression.from("2023-06-15:eow"); // Returns end of week containing June 15
97
+ ```
98
+
99
+ **Quarter Boundaries:**
100
+
101
+ ```javascript
102
+ // Quarters: Q1 (Jan-Mar), Q2 (Apr-Jun), Q3 (Jul-Sep), Q4 (Oct-Dec)
103
+ DateExpression.from("2023-05-15:soq"); // Returns 2023-04-01 (start of Q2)
104
+ DateExpression.from("2023-08-15:eoq"); // Returns 2023-09-30 (end of Q3)
105
+ ```
106
+
107
+ ## Class Architecture
108
+
109
+ ```mermaid
110
+ classDiagram
111
+ class DateExpression {
112
+ -raw: string
113
+ -rawDate: string
114
+ -modifier: Modifier | null
115
+ -dateParser: DateParser
116
+ +isNow: boolean
117
+ +isRelativeDate(): boolean
118
+ +isAbsoluteDate(): boolean
119
+ +hasModifier(): boolean
120
+ +toDate(): Date
121
+ +toAbsoluteString(): string
122
+ +modify(modifier: Modifier): DateExpression
123
+ +decomposeRelativeDate(): RelativeDateDecomposition | null
124
+ +toJSON(): object
125
+ +static isValid(expression: string): boolean
126
+ +static from(expression: string): DateExpression
127
+ +static now(): DateExpression
128
+ +static yesterday(): DateExpression
129
+ }
130
+
131
+ class Modifier {
132
+ -extreme: PeriodModifierExtreme
133
+ -unit: PeriodModifierTimeUnit
134
+
135
+ +static startOf(unit: PeriodModifierTimeUnit): Modifier
136
+ +static endOf(unit: PeriodModifierTimeUnit): Modifier
137
+ +static from(modifier: string): Modifier
138
+
139
+ +apply(date: Date): Date
140
+ +isStart(): boolean
141
+ +isEnd(): boolean
142
+ +toString(): string
143
+ +toJSON(): object
144
+ }
145
+
146
+ class DateParser {
147
+ <<interface>>
148
+ +toJSDate(raw: string): Date
149
+ }
150
+
151
+ class AbsoluteDateParser {
152
+ +toJSDate(raw: string): Date
153
+ +static isAbsoluteDate(raw: string): boolean
154
+ }
155
+
156
+ class RelativeDateParser {
157
+ +toJSDate(raw: string): Date
158
+ +decompose(raw: string): RelativeDateDecomposition
159
+ +static isRelativeDate(raw: string): boolean
160
+ }
161
+
162
+ %% Relationships
163
+ DateExpression --> Modifier : has optional
164
+ DateExpression --> DateParser : uses
165
+
166
+ DateParser <|.. AbsoluteDateParser : implements
167
+ DateParser <|.. RelativeDateParser : implements
168
+ ```
@@ -0,0 +1,74 @@
1
+ import { DateParser } from "./date-parser/DateParser";
2
+ import { AbsoluteDateParser } from "./date-parser/AbsoluteDateParser";
3
+ import { RelativeDateDecomposition, RelativeDateParser } from "./date-parser/RelativeDateParser";
4
+ import { Modifier } from "./Modifier";
5
+ export declare const INPUT_DATE_FORMAT = "yyyy-MM-dd";
6
+ export declare class DateExpression {
7
+ /**
8
+ * Matches date expressions, that consist of a date part and an optional modifier part.
9
+ * The date part can be a absolute date or a relative date.
10
+ * The modifier part can be a modifier string or null.
11
+ */
12
+ private static readonly DATE_EXPRESSION_REGEX;
13
+ readonly raw: string;
14
+ readonly rawDate: string;
15
+ readonly modifier: Modifier | null;
16
+ protected readonly dateParser: DateParser;
17
+ /**
18
+ * @param raw - The raw date expression
19
+ * @throws InvalidDateExpression
20
+ * @throws InvalidModifier
21
+ */
22
+ private constructor();
23
+ get isNow(): boolean;
24
+ isRelativeDate(): this is DateExpression & {
25
+ dateParser: RelativeDateParser;
26
+ };
27
+ isAbsoluteDate(): this is DateExpression & {
28
+ dateParser: AbsoluteDateParser;
29
+ };
30
+ hasModifier(): this is DateExpression & {
31
+ modifier: Modifier;
32
+ };
33
+ toDate(): Date;
34
+ toAbsoluteString(): string;
35
+ /**
36
+ * Creates a new DateExpression with the specified modifier.
37
+ * If the current expression already has a modifier, it will be replaced.
38
+ * @param modifier - The modifier to apply
39
+ * @returns A new DateExpression instance with the specified modifier
40
+ */
41
+ modify(modifier: Modifier): DateExpression;
42
+ decomposeRelativeDate(this: DateExpression & {
43
+ dateParser: RelativeDateParser;
44
+ }): RelativeDateDecomposition;
45
+ /**
46
+ * Checks if a date expression is valid
47
+ * @param expression - The date expression to check
48
+ * @returns True if the date expression is valid, false otherwise
49
+ */
50
+ static isValid(expression: string): boolean;
51
+ static from(expression: string): DateExpression;
52
+ static now(): DateExpression;
53
+ static yesterday(): DateExpression;
54
+ /**
55
+ * Parses a date expression and returns the date part and modifier part
56
+ * @param expression - The date expression to parse
57
+ * @returns Object with datePart and modifierPart (null if no modifier)
58
+ */
59
+ private static parse;
60
+ toJSON(): {
61
+ raw: string;
62
+ rawDate: string;
63
+ modifier: {
64
+ extreme: "s" | "e";
65
+ unit: "b" | "q" | "s" | "w" | "m" | "t" | "y";
66
+ } | null;
67
+ isNow: boolean;
68
+ isRelativeDate: boolean;
69
+ isAbsoluteDate: boolean;
70
+ hasModifier: boolean;
71
+ toDate: Date;
72
+ toAbsoluteString: string;
73
+ };
74
+ }
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DateExpression = exports.INPUT_DATE_FORMAT = void 0;
4
+ const DateParserFactory_1 = require("./date-parser/DateParserFactory");
5
+ const AbsoluteDateParser_1 = require("./date-parser/AbsoluteDateParser");
6
+ const RelativeDateParser_1 = require("./date-parser/RelativeDateParser");
7
+ const InvalidDateExpression_1 = require("./errors/InvalidDateExpression");
8
+ const Modifier_1 = require("./Modifier");
9
+ const date_fns_1 = require("date-fns");
10
+ // Date format compliant with ISO
11
+ exports.INPUT_DATE_FORMAT = "yyyy-MM-dd";
12
+ class DateExpression {
13
+ /**
14
+ * @param raw - The raw date expression
15
+ * @throws InvalidDateExpression
16
+ * @throws InvalidModifier
17
+ */
18
+ constructor(raw) {
19
+ this.raw = raw;
20
+ const { rawDatePart, rawModifierPart } = DateExpression.parse(raw);
21
+ this.modifier = rawModifierPart ? Modifier_1.Modifier.from(rawModifierPart) : null;
22
+ this.rawDate = rawDatePart;
23
+ // Parsing of the date part is delegated to DateParser
24
+ this.dateParser = DateParserFactory_1.DateParserFactory.create(rawDatePart);
25
+ }
26
+ get isNow() {
27
+ return this.rawDate === "now";
28
+ }
29
+ isRelativeDate() {
30
+ return this.dateParser instanceof RelativeDateParser_1.RelativeDateParser;
31
+ }
32
+ isAbsoluteDate() {
33
+ return this.dateParser instanceof AbsoluteDateParser_1.AbsoluteDateParser;
34
+ }
35
+ hasModifier() {
36
+ return this.modifier !== null;
37
+ }
38
+ toDate() {
39
+ var _a, _b;
40
+ const date = this.dateParser.toJSDate(this.rawDate);
41
+ return (_b = (_a = this.modifier) === null || _a === void 0 ? void 0 : _a.apply(date)) !== null && _b !== void 0 ? _b : date;
42
+ }
43
+ toAbsoluteString() {
44
+ return (0, date_fns_1.format)(this.toDate(), exports.INPUT_DATE_FORMAT);
45
+ }
46
+ /**
47
+ * Creates a new DateExpression with the specified modifier.
48
+ * If the current expression already has a modifier, it will be replaced.
49
+ * @param modifier - The modifier to apply
50
+ * @returns A new DateExpression instance with the specified modifier
51
+ */
52
+ modify(modifier) {
53
+ const newExpression = `${this.rawDate}:${modifier.toString()}`;
54
+ return DateExpression.from(newExpression);
55
+ }
56
+ decomposeRelativeDate() {
57
+ if (this.isRelativeDate()) {
58
+ return this.dateParser.decompose(this.rawDate);
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * Checks if a date expression is valid
64
+ * @param expression - The date expression to check
65
+ * @returns True if the date expression is valid, false otherwise
66
+ */
67
+ static isValid(expression) {
68
+ try {
69
+ DateExpression.from(expression);
70
+ return true;
71
+ }
72
+ catch (error) {
73
+ return false;
74
+ }
75
+ }
76
+ // Builders
77
+ static from(expression) {
78
+ return new DateExpression(expression);
79
+ }
80
+ static now() {
81
+ return new DateExpression("now");
82
+ }
83
+ static yesterday() {
84
+ return new DateExpression("-1d");
85
+ }
86
+ /**
87
+ * Parses a date expression and returns the date part and modifier part
88
+ * @param expression - The date expression to parse
89
+ * @returns Object with datePart and modifierPart (null if no modifier)
90
+ */
91
+ static parse(expression) {
92
+ const match = this.DATE_EXPRESSION_REGEX.exec(expression);
93
+ if (!match) {
94
+ throw new InvalidDateExpression_1.InvalidDateExpression(expression);
95
+ }
96
+ const [_, rawDatePart, rawModifierPart] = match;
97
+ return {
98
+ rawDatePart: rawDatePart.trim(),
99
+ rawModifierPart: (rawModifierPart === null || rawModifierPart === void 0 ? void 0 : rawModifierPart.trim()) || null,
100
+ };
101
+ }
102
+ toJSON() {
103
+ var _a, _b;
104
+ return {
105
+ raw: this.raw,
106
+ rawDate: this.rawDate,
107
+ modifier: (_b = (_a = this.modifier) === null || _a === void 0 ? void 0 : _a.toJSON()) !== null && _b !== void 0 ? _b : null,
108
+ isNow: this.isNow,
109
+ isRelativeDate: this.isRelativeDate(),
110
+ isAbsoluteDate: this.isAbsoluteDate(),
111
+ hasModifier: this.hasModifier(),
112
+ toDate: this.toDate(),
113
+ toAbsoluteString: this.toAbsoluteString(),
114
+ };
115
+ }
116
+ }
117
+ exports.DateExpression = DateExpression;
118
+ /**
119
+ * Matches date expressions, that consist of a date part and an optional modifier part.
120
+ * The date part can be a absolute date or a relative date.
121
+ * The modifier part can be a modifier string or null.
122
+ */
123
+ DateExpression.DATE_EXPRESSION_REGEX = /^(.+?)(?:\s*:\s*(.+?))?\s*$/;
124
+ //# sourceMappingURL=DateExpression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateExpression.js","sourceRoot":"","sources":["../src/DateExpression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};