@bgord/tools 0.16.1 → 0.17.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/dist/date-calculator.service.js +2 -2
- package/dist/day.vo.js +7 -7
- package/dist/duration.service.d.ts +37 -0
- package/dist/duration.service.js +77 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/revision.vo.d.ts +1 -1
- package/dist/revision.vo.js +1 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/date-calculator.service.ts +2 -2
- package/src/day.vo.ts +7 -7
- package/src/duration.service.ts +90 -0
- package/src/index.ts +1 -1
- package/src/revision.vo.ts +1 -5
- package/dist/time.service.d.ts +0 -36
- package/dist/time.service.js +0 -62
- package/src/time.service.ts +0 -95
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Duration } from "./duration.service";
|
|
2
2
|
import { Timestamp } from "./timestamp.vo";
|
|
3
3
|
export class DateCalculator {
|
|
4
4
|
static getStartOfDayTsInTz(config) {
|
|
5
|
-
const dayMs =
|
|
5
|
+
const dayMs = Duration.Days(1).ms;
|
|
6
6
|
// UTC midnight for the UTC date of `now`
|
|
7
7
|
const utcMidnight = Math.floor(config.now / dayMs) * dayMs;
|
|
8
8
|
// Candidate start of the local day (in UTC), anchored to the same UTC date
|
package/dist/day.vo.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
2
|
import { DayIsoId } from "./day-iso-id.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Duration } from "./duration.service";
|
|
4
4
|
import { Timestamp } from "./timestamp.vo";
|
|
5
5
|
export class Day extends DateRange {
|
|
6
6
|
constructor(start, end) {
|
|
7
7
|
super(start, end);
|
|
8
8
|
}
|
|
9
9
|
toIsoId() {
|
|
10
|
-
const midday = this.getStart() +
|
|
10
|
+
const midday = this.getStart() + Duration.Hours(12).ms;
|
|
11
11
|
return new Date(midday).toISOString().slice(0, 10);
|
|
12
12
|
}
|
|
13
13
|
previous() {
|
|
14
|
-
const shifted = this.getStart() -
|
|
14
|
+
const shifted = this.getStart() - Duration.Days(1).ms;
|
|
15
15
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
16
16
|
}
|
|
17
17
|
next() {
|
|
18
|
-
const shifted = this.getStart() +
|
|
18
|
+
const shifted = this.getStart() + Duration.Days(1).ms;
|
|
19
19
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
20
20
|
}
|
|
21
21
|
shift(count) {
|
|
22
|
-
const shifted = this.getStart() + count *
|
|
22
|
+
const shifted = this.getStart() + count * Duration.Days(1).ms;
|
|
23
23
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
24
24
|
}
|
|
25
25
|
static fromTimestamp(timestamp) {
|
|
26
26
|
const date = new Date(timestamp);
|
|
27
27
|
const startUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
28
|
-
const endUtc = startUtc +
|
|
28
|
+
const endUtc = startUtc + Duration.Days(1).ms - 1;
|
|
29
29
|
return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
30
30
|
}
|
|
31
31
|
static fromNow(now) {
|
|
@@ -34,7 +34,7 @@ export class Day extends DateRange {
|
|
|
34
34
|
static fromIsoId(isoId) {
|
|
35
35
|
const [year, month, day] = DayIsoId.parse(isoId).split("-").map(Number);
|
|
36
36
|
const startUtc = Date.UTC(year, month - 1, day);
|
|
37
|
-
const endUtc = startUtc +
|
|
37
|
+
const endUtc = startUtc + Duration.Days(1).ms - 1;
|
|
38
38
|
return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { type TimestampType } from "./timestamp.vo";
|
|
3
|
+
export declare const DurationMsError: {
|
|
4
|
+
readonly error: "duration.invalid";
|
|
5
|
+
};
|
|
6
|
+
export declare const DurationMsSchema: z.core.$ZodBranded<z.ZodNumber, "DurationMs">;
|
|
7
|
+
export type DurationMsType = z.infer<typeof DurationMsSchema>;
|
|
8
|
+
export declare class Duration {
|
|
9
|
+
private static readonly rounding;
|
|
10
|
+
private readonly valueMs;
|
|
11
|
+
private static readonly MS_IN_SECOND;
|
|
12
|
+
private static readonly MS_IN_MINUTE;
|
|
13
|
+
private static readonly MS_IN_HOUR;
|
|
14
|
+
private static readonly MS_IN_DAY;
|
|
15
|
+
private constructor();
|
|
16
|
+
static Days(value: number): Duration;
|
|
17
|
+
static Hours(value: number): Duration;
|
|
18
|
+
static Minutes(value: number): Duration;
|
|
19
|
+
static Seconds(value: number): Duration;
|
|
20
|
+
static Ms(value: number): Duration;
|
|
21
|
+
get days(): number;
|
|
22
|
+
get hours(): number;
|
|
23
|
+
get minutes(): number;
|
|
24
|
+
get seconds(): number;
|
|
25
|
+
get ms(): DurationMsType;
|
|
26
|
+
isLongerThan(another: Duration): boolean;
|
|
27
|
+
isShorterThan(another: Duration): boolean;
|
|
28
|
+
equals(other: Duration): boolean;
|
|
29
|
+
add(another: Duration): Duration;
|
|
30
|
+
subtract(another: Duration): Duration;
|
|
31
|
+
}
|
|
32
|
+
export declare const Time: {
|
|
33
|
+
Now(now: TimestampType): {
|
|
34
|
+
Add(duration: Duration): TimestampType;
|
|
35
|
+
Minus(duration: Duration): TimestampType;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { RoundToDecimal } from "./rounding.adapter";
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
export const DurationMsError = { error: "duration.invalid" };
|
|
5
|
+
export const DurationMsSchema = z
|
|
6
|
+
.number(DurationMsError)
|
|
7
|
+
.int(DurationMsError)
|
|
8
|
+
.refine(Number.isFinite, DurationMsError)
|
|
9
|
+
.brand("DurationMs");
|
|
10
|
+
export class Duration {
|
|
11
|
+
static rounding = new RoundToDecimal(2);
|
|
12
|
+
valueMs;
|
|
13
|
+
static MS_IN_SECOND = 1_000;
|
|
14
|
+
static MS_IN_MINUTE = 60_000;
|
|
15
|
+
static MS_IN_HOUR = 3_600_000;
|
|
16
|
+
static MS_IN_DAY = 86_400_000;
|
|
17
|
+
constructor(candidateMs) {
|
|
18
|
+
this.valueMs = DurationMsSchema.parse(candidateMs);
|
|
19
|
+
}
|
|
20
|
+
static Days(value) {
|
|
21
|
+
return new Duration(value * Duration.MS_IN_DAY);
|
|
22
|
+
}
|
|
23
|
+
static Hours(value) {
|
|
24
|
+
return new Duration(value * Duration.MS_IN_HOUR);
|
|
25
|
+
}
|
|
26
|
+
static Minutes(value) {
|
|
27
|
+
return new Duration(value * Duration.MS_IN_MINUTE);
|
|
28
|
+
}
|
|
29
|
+
static Seconds(value) {
|
|
30
|
+
return new Duration(value * Duration.MS_IN_SECOND);
|
|
31
|
+
}
|
|
32
|
+
static Ms(value) {
|
|
33
|
+
return new Duration(value);
|
|
34
|
+
}
|
|
35
|
+
get days() {
|
|
36
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_DAY);
|
|
37
|
+
}
|
|
38
|
+
get hours() {
|
|
39
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_HOUR);
|
|
40
|
+
}
|
|
41
|
+
get minutes() {
|
|
42
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_MINUTE);
|
|
43
|
+
}
|
|
44
|
+
get seconds() {
|
|
45
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_SECOND);
|
|
46
|
+
}
|
|
47
|
+
get ms() {
|
|
48
|
+
return this.valueMs;
|
|
49
|
+
}
|
|
50
|
+
isLongerThan(another) {
|
|
51
|
+
return this.valueMs > another.valueMs;
|
|
52
|
+
}
|
|
53
|
+
isShorterThan(another) {
|
|
54
|
+
return this.valueMs < another.valueMs;
|
|
55
|
+
}
|
|
56
|
+
equals(other) {
|
|
57
|
+
return this.valueMs === other.valueMs;
|
|
58
|
+
}
|
|
59
|
+
add(another) {
|
|
60
|
+
return Duration.Ms(this.valueMs + another.valueMs);
|
|
61
|
+
}
|
|
62
|
+
subtract(another) {
|
|
63
|
+
return Duration.Ms(this.valueMs - another.valueMs);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export const Time = {
|
|
67
|
+
Now(now) {
|
|
68
|
+
return {
|
|
69
|
+
Add(duration) {
|
|
70
|
+
return Timestamp.parse(now + duration.ms);
|
|
71
|
+
},
|
|
72
|
+
Minus(duration) {
|
|
73
|
+
return Timestamp.parse(now - duration.ms);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./day-iso-id.vo";
|
|
|
10
10
|
export * from "./directory-path-absolute.vo";
|
|
11
11
|
export * from "./directory-path-relative.vo";
|
|
12
12
|
export * from "./dll.service";
|
|
13
|
+
export * from "./duration.service";
|
|
13
14
|
export * from "./email-mask.service";
|
|
14
15
|
export * from "./etags.vo";
|
|
15
16
|
export * from "./extension.vo";
|
|
@@ -57,7 +58,6 @@ export * from "./stopwatch.service";
|
|
|
57
58
|
export * from "./streak-calculator.service";
|
|
58
59
|
export * from "./sum.service";
|
|
59
60
|
export * from "./thousands-separator.service";
|
|
60
|
-
export * from "./time.service";
|
|
61
61
|
export * from "./time-zone-offset-value.vo";
|
|
62
62
|
export * from "./timestamp.vo";
|
|
63
63
|
export * from "./timezone.vo";
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./day-iso-id.vo";
|
|
|
10
10
|
export * from "./directory-path-absolute.vo";
|
|
11
11
|
export * from "./directory-path-relative.vo";
|
|
12
12
|
export * from "./dll.service";
|
|
13
|
+
export * from "./duration.service";
|
|
13
14
|
export * from "./email-mask.service";
|
|
14
15
|
export * from "./etags.vo";
|
|
15
16
|
export * from "./extension.vo";
|
|
@@ -57,7 +58,6 @@ export * from "./stopwatch.service";
|
|
|
57
58
|
export * from "./streak-calculator.service";
|
|
58
59
|
export * from "./sum.service";
|
|
59
60
|
export * from "./thousands-separator.service";
|
|
60
|
-
export * from "./time.service";
|
|
61
61
|
export * from "./time-zone-offset-value.vo";
|
|
62
62
|
export * from "./timestamp.vo";
|
|
63
63
|
export * from "./timezone.vo";
|
package/dist/revision.vo.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ETag, WeakETag } from "./etags.vo";
|
|
|
3
3
|
export declare const RevisionValueError: {
|
|
4
4
|
readonly error: "invalid.revision.value";
|
|
5
5
|
};
|
|
6
|
-
export declare const RevisionValue: z.
|
|
6
|
+
export declare const RevisionValue: z.ZodNumber;
|
|
7
7
|
export type RevisionValueType = z.infer<typeof RevisionValue>;
|
|
8
8
|
export declare const RevisionInvalidErrorMessage: "revision.invalid";
|
|
9
9
|
export declare const RevisionMismatchErrorMessage: "revision.mismatch";
|
package/dist/revision.vo.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
export const RevisionValueError = { error: "invalid.revision.value" };
|
|
3
|
-
export const RevisionValue = z
|
|
4
|
-
.number(RevisionValueError)
|
|
5
|
-
.int(RevisionValueError)
|
|
6
|
-
.min(0, RevisionValueError)
|
|
7
|
-
.brand("RevisionValue");
|
|
3
|
+
export const RevisionValue = z.number(RevisionValueError).int(RevisionValueError).min(0, RevisionValueError);
|
|
8
4
|
export const RevisionInvalidErrorMessage = "revision.invalid";
|
|
9
5
|
export const RevisionMismatchErrorMessage = "revision.mismatch";
|
|
10
6
|
export class Revision {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/age.vo.ts","../src/api-key.vo.ts","../src/basename.vo.ts","../src/clock-format.service.ts","../src/clock.vo.ts","../src/date-calculator.service.ts","../src/date-formatter.service.ts","../src/date-range.vo.ts","../src/day-iso-id.vo.ts","../src/day.vo.ts","../src/directory-path-absolute.vo.ts","../src/directory-path-relative.vo.ts","../src/dll.service.ts","../src/email-mask.service.ts","../src/etags.vo.ts","../src/extension.vo.ts","../src/feature-flag.vo.ts","../src/file-path-absolute-schema.vo.ts","../src/file-path-relative-schema.vo.ts","../src/file-path.vo.ts","../src/filename-from-string.vo.ts","../src/filename-suffix.vo.ts","../src/filename.vo.ts","../src/height.vo.ts","../src/hour-format.service.ts","../src/hour.vo.ts","../src/iban-mask.service.ts","../src/iban.vo.ts","../src/image.vo.ts","../src/index.ts","../src/language.vo.ts","../src/mean.service.ts","../src/mime-types.vo.ts","../src/mime.vo.ts","../src/min-max-scaler.service.ts","../src/minute.vo.ts","../src/money.vo.ts","../src/month-iso-id.vo.ts","../src/month.vo.ts","../src/noop.service.ts","../src/notification-template.vo.ts","../src/object-key.vo.ts","../src/outlier-detector.service.ts","../src/package-version.vo.ts","../src/pagination.service.ts","../src/percentage.service.ts","../src/population-standard-deviation.service.ts","../src/quarter-iso-id.vo.ts","../src/quarter.vo.ts","../src/random.service.ts","../src/rate-limiter.service.ts","../src/relative-date.vo.ts","../src/reordering.service.ts","../src/revision.vo.ts","../src/rounding.adapter.ts","../src/rounding.port.ts","../src/simple-linear-regression.service.ts","../src/size.vo.ts","../src/stopwatch.service.ts","../src/streak-calculator.service.ts","../src/sum.service.ts","../src/thousands-separator.service.ts","../src/time-zone-offset-value.vo.ts","../src/
|
|
1
|
+
{"root":["../src/age.vo.ts","../src/api-key.vo.ts","../src/basename.vo.ts","../src/clock-format.service.ts","../src/clock.vo.ts","../src/date-calculator.service.ts","../src/date-formatter.service.ts","../src/date-range.vo.ts","../src/day-iso-id.vo.ts","../src/day.vo.ts","../src/directory-path-absolute.vo.ts","../src/directory-path-relative.vo.ts","../src/dll.service.ts","../src/duration.service.ts","../src/email-mask.service.ts","../src/etags.vo.ts","../src/extension.vo.ts","../src/feature-flag.vo.ts","../src/file-path-absolute-schema.vo.ts","../src/file-path-relative-schema.vo.ts","../src/file-path.vo.ts","../src/filename-from-string.vo.ts","../src/filename-suffix.vo.ts","../src/filename.vo.ts","../src/height.vo.ts","../src/hour-format.service.ts","../src/hour.vo.ts","../src/iban-mask.service.ts","../src/iban.vo.ts","../src/image.vo.ts","../src/index.ts","../src/language.vo.ts","../src/mean.service.ts","../src/mime-types.vo.ts","../src/mime.vo.ts","../src/min-max-scaler.service.ts","../src/minute.vo.ts","../src/money.vo.ts","../src/month-iso-id.vo.ts","../src/month.vo.ts","../src/noop.service.ts","../src/notification-template.vo.ts","../src/object-key.vo.ts","../src/outlier-detector.service.ts","../src/package-version.vo.ts","../src/pagination.service.ts","../src/percentage.service.ts","../src/population-standard-deviation.service.ts","../src/quarter-iso-id.vo.ts","../src/quarter.vo.ts","../src/random.service.ts","../src/rate-limiter.service.ts","../src/relative-date.vo.ts","../src/reordering.service.ts","../src/revision.vo.ts","../src/rounding.adapter.ts","../src/rounding.port.ts","../src/simple-linear-regression.service.ts","../src/size.vo.ts","../src/stopwatch.service.ts","../src/streak-calculator.service.ts","../src/sum.service.ts","../src/thousands-separator.service.ts","../src/time-zone-offset-value.vo.ts","../src/timestamp.vo.ts","../src/timezone.vo.ts","../src/ts-utils.ts","../src/visually-unambiguous-characters-generator.service.ts","../src/week-iso-id.vo.ts","../src/week.vo.ts","../src/weekday.vo.ts","../src/weight.vo.ts","../src/year-iso-id.vo.ts","../src/year.vo.ts","../src/z-score.service.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -37,6 +37,7 @@ src/
|
|
|
37
37
|
├── directory-path-absolute.vo.ts
|
|
38
38
|
├── directory-path-relative.vo.ts
|
|
39
39
|
├── dll.service.ts
|
|
40
|
+
├── duration.service.ts
|
|
40
41
|
├── email-mask.service.ts
|
|
41
42
|
├── etags.vo.ts
|
|
42
43
|
├── extension.vo.ts
|
|
@@ -86,7 +87,6 @@ src/
|
|
|
86
87
|
├── sum.service.ts
|
|
87
88
|
├── thousands-separator.service.ts
|
|
88
89
|
├── time-zone-offset-value.vo.ts
|
|
89
|
-
├── time.service.ts
|
|
90
90
|
├── timestamp.vo.ts
|
|
91
91
|
├── timezone.vo.ts
|
|
92
92
|
├── ts-utils.ts
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Duration } from "./duration.service";
|
|
2
2
|
import { Timestamp, type TimestampType } from "./timestamp.vo";
|
|
3
3
|
|
|
4
4
|
type GetStartOfDayTsInTzConfigType = { now: TimestampType; timeZoneOffsetMs: number };
|
|
5
5
|
|
|
6
6
|
export class DateCalculator {
|
|
7
7
|
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType): TimestampType {
|
|
8
|
-
const dayMs =
|
|
8
|
+
const dayMs = Duration.Days(1).ms;
|
|
9
9
|
|
|
10
10
|
// UTC midnight for the UTC date of `now`
|
|
11
11
|
const utcMidnight = Math.floor(config.now / dayMs) * dayMs;
|
package/src/day.vo.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
2
|
import { DayIsoId, type DayIsoIdType } from "./day-iso-id.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Duration } from "./duration.service";
|
|
4
4
|
import { Timestamp, type TimestampType } from "./timestamp.vo";
|
|
5
5
|
|
|
6
6
|
export class Day extends DateRange {
|
|
@@ -9,25 +9,25 @@ export class Day extends DateRange {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
toIsoId(): DayIsoIdType {
|
|
12
|
-
const midday = this.getStart() +
|
|
12
|
+
const midday = this.getStart() + Duration.Hours(12).ms;
|
|
13
13
|
|
|
14
14
|
return new Date(midday).toISOString().slice(0, 10) as DayIsoIdType;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
previous(): Day {
|
|
18
|
-
const shifted = this.getStart() -
|
|
18
|
+
const shifted = this.getStart() - Duration.Days(1).ms;
|
|
19
19
|
|
|
20
20
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
next(): Day {
|
|
24
|
-
const shifted = this.getStart() +
|
|
24
|
+
const shifted = this.getStart() + Duration.Days(1).ms;
|
|
25
25
|
|
|
26
26
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
shift(count: number): Day {
|
|
30
|
-
const shifted = this.getStart() + count *
|
|
30
|
+
const shifted = this.getStart() + count * Duration.Days(1).ms;
|
|
31
31
|
|
|
32
32
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
33
33
|
}
|
|
@@ -35,7 +35,7 @@ export class Day extends DateRange {
|
|
|
35
35
|
static fromTimestamp(timestamp: TimestampType): Day {
|
|
36
36
|
const date = new Date(timestamp);
|
|
37
37
|
const startUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
38
|
-
const endUtc = startUtc +
|
|
38
|
+
const endUtc = startUtc + Duration.Days(1).ms - 1;
|
|
39
39
|
|
|
40
40
|
return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
41
41
|
}
|
|
@@ -47,7 +47,7 @@ export class Day extends DateRange {
|
|
|
47
47
|
static fromIsoId(isoId: DayIsoIdType): Day {
|
|
48
48
|
const [year, month, day] = DayIsoId.parse(isoId).split("-").map(Number);
|
|
49
49
|
const startUtc = Date.UTC(year, month - 1, day);
|
|
50
|
-
const endUtc = startUtc +
|
|
50
|
+
const endUtc = startUtc + Duration.Days(1).ms - 1;
|
|
51
51
|
|
|
52
52
|
return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
53
53
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { RoundToDecimal } from "./rounding.adapter";
|
|
3
|
+
import type { RoundingPort } from "./rounding.port";
|
|
4
|
+
import { Timestamp, type TimestampType } from "./timestamp.vo";
|
|
5
|
+
|
|
6
|
+
export const DurationMsError = { error: "duration.invalid" } as const;
|
|
7
|
+
|
|
8
|
+
export const DurationMsSchema = z
|
|
9
|
+
.number(DurationMsError)
|
|
10
|
+
.int(DurationMsError)
|
|
11
|
+
.refine(Number.isFinite, DurationMsError)
|
|
12
|
+
.brand("DurationMs");
|
|
13
|
+
|
|
14
|
+
export type DurationMsType = z.infer<typeof DurationMsSchema>;
|
|
15
|
+
|
|
16
|
+
export class Duration {
|
|
17
|
+
private static readonly rounding: RoundingPort = new RoundToDecimal(2);
|
|
18
|
+
private readonly valueMs: DurationMsType;
|
|
19
|
+
|
|
20
|
+
private static readonly MS_IN_SECOND = 1_000;
|
|
21
|
+
private static readonly MS_IN_MINUTE = 60_000;
|
|
22
|
+
private static readonly MS_IN_HOUR = 3_600_000;
|
|
23
|
+
private static readonly MS_IN_DAY = 86_400_000;
|
|
24
|
+
|
|
25
|
+
private constructor(candidateMs: number) {
|
|
26
|
+
this.valueMs = DurationMsSchema.parse(candidateMs);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static Days(value: number): Duration {
|
|
30
|
+
return new Duration(value * Duration.MS_IN_DAY);
|
|
31
|
+
}
|
|
32
|
+
static Hours(value: number): Duration {
|
|
33
|
+
return new Duration(value * Duration.MS_IN_HOUR);
|
|
34
|
+
}
|
|
35
|
+
static Minutes(value: number): Duration {
|
|
36
|
+
return new Duration(value * Duration.MS_IN_MINUTE);
|
|
37
|
+
}
|
|
38
|
+
static Seconds(value: number): Duration {
|
|
39
|
+
return new Duration(value * Duration.MS_IN_SECOND);
|
|
40
|
+
}
|
|
41
|
+
static Ms(value: number): Duration {
|
|
42
|
+
return new Duration(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get days(): number {
|
|
46
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_DAY);
|
|
47
|
+
}
|
|
48
|
+
get hours(): number {
|
|
49
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_HOUR);
|
|
50
|
+
}
|
|
51
|
+
get minutes(): number {
|
|
52
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_MINUTE);
|
|
53
|
+
}
|
|
54
|
+
get seconds(): number {
|
|
55
|
+
return Duration.rounding.round(this.valueMs / Duration.MS_IN_SECOND);
|
|
56
|
+
}
|
|
57
|
+
get ms(): DurationMsType {
|
|
58
|
+
return this.valueMs;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isLongerThan(another: Duration): boolean {
|
|
62
|
+
return this.valueMs > another.valueMs;
|
|
63
|
+
}
|
|
64
|
+
isShorterThan(another: Duration): boolean {
|
|
65
|
+
return this.valueMs < another.valueMs;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
equals(other: Duration): boolean {
|
|
69
|
+
return this.valueMs === other.valueMs;
|
|
70
|
+
}
|
|
71
|
+
add(another: Duration): Duration {
|
|
72
|
+
return Duration.Ms(this.valueMs + another.valueMs);
|
|
73
|
+
}
|
|
74
|
+
subtract(another: Duration): Duration {
|
|
75
|
+
return Duration.Ms(this.valueMs - another.valueMs);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const Time = {
|
|
80
|
+
Now(now: TimestampType) {
|
|
81
|
+
return {
|
|
82
|
+
Add(duration: Duration): TimestampType {
|
|
83
|
+
return Timestamp.parse(now + duration.ms);
|
|
84
|
+
},
|
|
85
|
+
Minus(duration: Duration): TimestampType {
|
|
86
|
+
return Timestamp.parse(now - duration.ms);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./day-iso-id.vo";
|
|
|
10
10
|
export * from "./directory-path-absolute.vo";
|
|
11
11
|
export * from "./directory-path-relative.vo";
|
|
12
12
|
export * from "./dll.service";
|
|
13
|
+
export * from "./duration.service";
|
|
13
14
|
export * from "./email-mask.service";
|
|
14
15
|
export * from "./etags.vo";
|
|
15
16
|
export * from "./extension.vo";
|
|
@@ -57,7 +58,6 @@ export * from "./stopwatch.service";
|
|
|
57
58
|
export * from "./streak-calculator.service";
|
|
58
59
|
export * from "./sum.service";
|
|
59
60
|
export * from "./thousands-separator.service";
|
|
60
|
-
export * from "./time.service";
|
|
61
61
|
export * from "./time-zone-offset-value.vo";
|
|
62
62
|
export * from "./timestamp.vo";
|
|
63
63
|
export * from "./timezone.vo";
|
package/src/revision.vo.ts
CHANGED
|
@@ -3,11 +3,7 @@ import type { ETag, WeakETag } from "./etags.vo";
|
|
|
3
3
|
|
|
4
4
|
export const RevisionValueError = { error: "invalid.revision.value" } as const;
|
|
5
5
|
|
|
6
|
-
export const RevisionValue = z
|
|
7
|
-
.number(RevisionValueError)
|
|
8
|
-
.int(RevisionValueError)
|
|
9
|
-
.min(0, RevisionValueError)
|
|
10
|
-
.brand("RevisionValue");
|
|
6
|
+
export const RevisionValue = z.number(RevisionValueError).int(RevisionValueError).min(0, RevisionValueError);
|
|
11
7
|
|
|
12
8
|
export type RevisionValueType = z.infer<typeof RevisionValue>;
|
|
13
9
|
|
package/dist/time.service.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { TimestampType } from "./timestamp.vo";
|
|
2
|
-
export interface TimeResultInterface {
|
|
3
|
-
readonly days: number;
|
|
4
|
-
readonly hours: number;
|
|
5
|
-
readonly minutes: number;
|
|
6
|
-
readonly seconds: number;
|
|
7
|
-
readonly ms: TimestampType;
|
|
8
|
-
isAfter(another: TimeResultInterface): boolean;
|
|
9
|
-
isBefore(another: TimeResultInterface): boolean;
|
|
10
|
-
add(another: TimeResultInterface): TimeResultInterface;
|
|
11
|
-
subtract(another: TimeResultInterface): TimeResultInterface;
|
|
12
|
-
}
|
|
13
|
-
export declare class TimeResult implements TimeResultInterface {
|
|
14
|
-
private readonly valueMs;
|
|
15
|
-
constructor(ms: TimestampType);
|
|
16
|
-
get days(): number;
|
|
17
|
-
get hours(): number;
|
|
18
|
-
get minutes(): number;
|
|
19
|
-
get seconds(): number;
|
|
20
|
-
get ms(): TimestampType;
|
|
21
|
-
isAfter(another: TimeResultInterface): boolean;
|
|
22
|
-
isBefore(another: TimeResultInterface): boolean;
|
|
23
|
-
add(another: TimeResultInterface): TimeResultInterface;
|
|
24
|
-
subtract(another: TimeResultInterface): TimeResultInterface;
|
|
25
|
-
}
|
|
26
|
-
export declare class Time {
|
|
27
|
-
static Days(value: number): TimeResultInterface;
|
|
28
|
-
static Hours(value: number): TimeResultInterface;
|
|
29
|
-
static Minutes(value: number): TimeResultInterface;
|
|
30
|
-
static Seconds(value: number): TimeResultInterface;
|
|
31
|
-
static Ms(value: number): TimeResultInterface;
|
|
32
|
-
static Now(now: TimestampType): {
|
|
33
|
-
Minus(time: TimeResultInterface): TimeResultInterface;
|
|
34
|
-
Add(time: TimeResultInterface): TimeResultInterface;
|
|
35
|
-
};
|
|
36
|
-
}
|
package/dist/time.service.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { RoundToDecimal } from "./rounding.adapter";
|
|
2
|
-
const rounding = new RoundToDecimal(2);
|
|
3
|
-
export class TimeResult {
|
|
4
|
-
valueMs;
|
|
5
|
-
constructor(ms) {
|
|
6
|
-
this.valueMs = ms;
|
|
7
|
-
}
|
|
8
|
-
get days() {
|
|
9
|
-
return rounding.round(this.valueMs / 86_400_000);
|
|
10
|
-
}
|
|
11
|
-
get hours() {
|
|
12
|
-
return rounding.round(this.valueMs / 3_600_000);
|
|
13
|
-
}
|
|
14
|
-
get minutes() {
|
|
15
|
-
return rounding.round(this.valueMs / 60_000);
|
|
16
|
-
}
|
|
17
|
-
get seconds() {
|
|
18
|
-
return rounding.round(this.valueMs / 1_000);
|
|
19
|
-
}
|
|
20
|
-
get ms() {
|
|
21
|
-
return this.valueMs;
|
|
22
|
-
}
|
|
23
|
-
isAfter(another) {
|
|
24
|
-
return this.valueMs > another.ms;
|
|
25
|
-
}
|
|
26
|
-
isBefore(another) {
|
|
27
|
-
return this.valueMs < another.ms;
|
|
28
|
-
}
|
|
29
|
-
add(another) {
|
|
30
|
-
return new TimeResult((this.valueMs + another.ms));
|
|
31
|
-
}
|
|
32
|
-
subtract(another) {
|
|
33
|
-
return new TimeResult((this.valueMs - another.ms));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export class Time {
|
|
37
|
-
static Days(value) {
|
|
38
|
-
return new TimeResult((value * 86_400_000));
|
|
39
|
-
}
|
|
40
|
-
static Hours(value) {
|
|
41
|
-
return new TimeResult((value * 3_600_000));
|
|
42
|
-
}
|
|
43
|
-
static Minutes(value) {
|
|
44
|
-
return new TimeResult((value * 60_000));
|
|
45
|
-
}
|
|
46
|
-
static Seconds(value) {
|
|
47
|
-
return new TimeResult((value * 1_000));
|
|
48
|
-
}
|
|
49
|
-
static Ms(value) {
|
|
50
|
-
return new TimeResult(value);
|
|
51
|
-
}
|
|
52
|
-
static Now(now) {
|
|
53
|
-
return {
|
|
54
|
-
Minus(time) {
|
|
55
|
-
return Time.Ms(now - time.ms);
|
|
56
|
-
},
|
|
57
|
-
Add(time) {
|
|
58
|
-
return Time.Ms(now + time.ms);
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
package/src/time.service.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { RoundToDecimal } from "./rounding.adapter";
|
|
2
|
-
import type { TimestampType } from "./timestamp.vo";
|
|
3
|
-
|
|
4
|
-
const rounding = new RoundToDecimal(2);
|
|
5
|
-
|
|
6
|
-
export interface TimeResultInterface {
|
|
7
|
-
readonly days: number;
|
|
8
|
-
readonly hours: number;
|
|
9
|
-
readonly minutes: number;
|
|
10
|
-
readonly seconds: number;
|
|
11
|
-
readonly ms: TimestampType;
|
|
12
|
-
|
|
13
|
-
isAfter(another: TimeResultInterface): boolean;
|
|
14
|
-
isBefore(another: TimeResultInterface): boolean;
|
|
15
|
-
|
|
16
|
-
add(another: TimeResultInterface): TimeResultInterface;
|
|
17
|
-
subtract(another: TimeResultInterface): TimeResultInterface;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class TimeResult implements TimeResultInterface {
|
|
21
|
-
private readonly valueMs: TimestampType;
|
|
22
|
-
|
|
23
|
-
constructor(ms: TimestampType) {
|
|
24
|
-
this.valueMs = ms;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
get days(): number {
|
|
28
|
-
return rounding.round(this.valueMs / 86_400_000);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
get hours(): number {
|
|
32
|
-
return rounding.round(this.valueMs / 3_600_000);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get minutes(): number {
|
|
36
|
-
return rounding.round(this.valueMs / 60_000);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get seconds(): number {
|
|
40
|
-
return rounding.round(this.valueMs / 1_000);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get ms(): TimestampType {
|
|
44
|
-
return this.valueMs;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
isAfter(another: TimeResultInterface): boolean {
|
|
48
|
-
return this.valueMs > another.ms;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
isBefore(another: TimeResultInterface): boolean {
|
|
52
|
-
return this.valueMs < another.ms;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
add(another: TimeResultInterface): TimeResultInterface {
|
|
56
|
-
return new TimeResult((this.valueMs + another.ms) as TimestampType);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
subtract(another: TimeResultInterface): TimeResultInterface {
|
|
60
|
-
return new TimeResult((this.valueMs - another.ms) as TimestampType);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export class Time {
|
|
65
|
-
static Days(value: number): TimeResultInterface {
|
|
66
|
-
return new TimeResult((value * 86_400_000) as TimestampType);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
static Hours(value: number): TimeResultInterface {
|
|
70
|
-
return new TimeResult((value * 3_600_000) as TimestampType);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
static Minutes(value: number): TimeResultInterface {
|
|
74
|
-
return new TimeResult((value * 60_000) as TimestampType);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
static Seconds(value: number): TimeResultInterface {
|
|
78
|
-
return new TimeResult((value * 1_000) as TimestampType);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
static Ms(value: number): TimeResultInterface {
|
|
82
|
-
return new TimeResult(value as TimestampType);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
static Now(now: TimestampType) {
|
|
86
|
-
return {
|
|
87
|
-
Minus(time: TimeResultInterface): TimeResultInterface {
|
|
88
|
-
return Time.Ms(now - time.ms);
|
|
89
|
-
},
|
|
90
|
-
Add(time: TimeResultInterface): TimeResultInterface {
|
|
91
|
-
return Time.Ms(now + time.ms);
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
}
|