@bgord/tools 1.1.1 → 1.1.3
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/age.vo.d.ts +5 -5
- package/dist/age.vo.js +3 -3
- package/dist/clock.vo.d.ts +2 -2
- package/dist/clock.vo.js +3 -3
- package/dist/date-calculator.service.d.ts +3 -3
- package/dist/date-calculator.service.js +2 -2
- package/dist/date-range.vo.d.ts +6 -6
- package/dist/day.vo.d.ts +5 -3
- package/dist/day.vo.js +6 -3
- package/dist/hour.vo.d.ts +4 -2
- package/dist/hour.vo.js +5 -1
- package/dist/minute.vo.d.ts +4 -2
- package/dist/minute.vo.js +5 -1
- package/dist/month.vo.d.ts +5 -3
- package/dist/month.vo.js +8 -5
- package/dist/quarter.vo.d.ts +5 -3
- package/dist/quarter.vo.js +7 -4
- package/dist/rate-limiter.service.d.ts +2 -2
- package/dist/relative-date.vo.d.ts +3 -3
- package/dist/stopwatch.service.d.ts +2 -2
- package/dist/stopwatch.service.js +2 -2
- package/dist/timestamp.vo.d.ts +11 -11
- package/dist/timestamp.vo.js +5 -5
- package/dist/week.vo.d.ts +5 -3
- package/dist/week.vo.js +8 -5
- package/dist/weekday.vo.d.ts +4 -2
- package/dist/weekday.vo.js +5 -1
- package/dist/year.vo.d.ts +5 -3
- package/dist/year.vo.js +8 -5
- package/package.json +2 -2
- package/src/age.vo.ts +4 -4
- package/src/clock.vo.ts +4 -4
- package/src/date-calculator.service.ts +4 -4
- package/src/date-range.vo.ts +7 -7
- package/src/day.vo.ts +10 -5
- package/src/hour.vo.ts +7 -2
- package/src/minute.vo.ts +7 -2
- package/src/month.vo.ts +12 -7
- package/src/quarter.vo.ts +11 -6
- package/src/rate-limiter.service.ts +3 -3
- package/src/relative-date.vo.ts +4 -4
- package/src/stopwatch.service.ts +3 -3
- package/src/timestamp.vo.ts +15 -15
- package/src/week.vo.ts +12 -7
- package/src/weekday.vo.ts +7 -2
- package/src/year.vo.ts +12 -7
package/dist/age.vo.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Timestamp } from "./timestamp.vo";
|
|
2
2
|
export declare const AgeError: {
|
|
3
3
|
readonly FutureBirthdate: "age.future.birthdate";
|
|
4
4
|
};
|
|
@@ -8,13 +8,13 @@ export declare class Age {
|
|
|
8
8
|
static readonly MAX: number;
|
|
9
9
|
private constructor();
|
|
10
10
|
static fromValue(candidate: number): Age;
|
|
11
|
-
static
|
|
12
|
-
birthdate:
|
|
13
|
-
now:
|
|
11
|
+
static fromBirthdateTimestamp(params: {
|
|
12
|
+
birthdate: Timestamp;
|
|
13
|
+
now: Timestamp;
|
|
14
14
|
}): Age;
|
|
15
15
|
static fromBirthdate(candidate: {
|
|
16
16
|
birthdate: string;
|
|
17
|
-
now:
|
|
17
|
+
now: Timestamp;
|
|
18
18
|
}): Age;
|
|
19
19
|
get(): number;
|
|
20
20
|
equals(other: Age): boolean;
|
package/dist/age.vo.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { differenceInYears } from "date-fns";
|
|
2
2
|
import { AgeYears, AgeYearsConstraints } from "./age-years.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
4
|
export const AgeError = { FutureBirthdate: "age.future.birthdate" };
|
|
5
5
|
export class Age {
|
|
6
6
|
value;
|
|
@@ -12,13 +12,13 @@ export class Age {
|
|
|
12
12
|
static fromValue(candidate) {
|
|
13
13
|
return new Age(AgeYears.parse(candidate));
|
|
14
14
|
}
|
|
15
|
-
static
|
|
15
|
+
static fromBirthdateTimestamp(params) {
|
|
16
16
|
if (params.birthdate.isAfter(params.now))
|
|
17
17
|
throw new Error(AgeError.FutureBirthdate);
|
|
18
18
|
return Age.fromValue(differenceInYears(params.now.ms, params.birthdate.ms));
|
|
19
19
|
}
|
|
20
20
|
static fromBirthdate(candidate) {
|
|
21
|
-
const birthdate =
|
|
21
|
+
const birthdate = Timestamp.fromNumber(new Date(candidate.birthdate).getTime());
|
|
22
22
|
if (birthdate.isAfter(candidate.now))
|
|
23
23
|
throw new Error(AgeError.FutureBirthdate);
|
|
24
24
|
return Age.fromValue(differenceInYears(candidate.now.ms, birthdate.ms));
|
package/dist/clock.vo.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ import { Hour } from "./hour.vo";
|
|
|
3
3
|
import type { HourSchemaType } from "./hour-schema.vo";
|
|
4
4
|
import { Minute } from "./minute.vo";
|
|
5
5
|
import type { MinuteSchemaType } from "./minute-schema.vo";
|
|
6
|
-
import type {
|
|
6
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
7
7
|
export declare class Clock {
|
|
8
8
|
private readonly hour;
|
|
9
9
|
private readonly minute;
|
|
10
10
|
private readonly formatter;
|
|
11
11
|
constructor(hour: Hour, minute: Minute, formatter?: ClockFormatter);
|
|
12
|
-
static
|
|
12
|
+
static fromTimestamp(timestamp: Timestamp, formatter?: ClockFormatter): Clock;
|
|
13
13
|
get(): {
|
|
14
14
|
hour: HourSchemaType;
|
|
15
15
|
minute: MinuteSchemaType;
|
package/dist/clock.vo.js
CHANGED
|
@@ -10,9 +10,9 @@ export class Clock {
|
|
|
10
10
|
this.minute = minute;
|
|
11
11
|
this.formatter = formatter ?? ClockFormatters.TWENTY_FOUR_HOURS;
|
|
12
12
|
}
|
|
13
|
-
static
|
|
14
|
-
const hour = Hour.
|
|
15
|
-
const minute = Minute.
|
|
13
|
+
static fromTimestamp(timestamp, formatter) {
|
|
14
|
+
const hour = Hour.fromTimestamp(timestamp);
|
|
15
|
+
const minute = Minute.fromTimestamp(timestamp);
|
|
16
16
|
return new Clock(hour, minute, formatter);
|
|
17
17
|
}
|
|
18
18
|
get() {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Duration } from "./duration.service";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
3
|
type GetStartOfDayTsInTzConfigType = {
|
|
4
|
-
now:
|
|
4
|
+
now: Timestamp;
|
|
5
5
|
timeZoneOffset: Duration;
|
|
6
6
|
};
|
|
7
7
|
export declare class DateCalculator {
|
|
8
|
-
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType):
|
|
8
|
+
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType): Timestamp;
|
|
9
9
|
}
|
|
10
10
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Duration } from "./duration.service";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
3
|
export class DateCalculator {
|
|
4
4
|
static getStartOfDayTsInTz(config) {
|
|
5
5
|
const dayMs = Duration.Days(1).ms;
|
|
6
|
-
const utcMidnightOfNow =
|
|
6
|
+
const utcMidnightOfNow = Timestamp.fromNumber(Math.floor(config.now.ms / dayMs) * dayMs);
|
|
7
7
|
let startOfDayInTz = utcMidnightOfNow.add(config.timeZoneOffset);
|
|
8
8
|
if (startOfDayInTz.isAfter(config.now))
|
|
9
9
|
startOfDayInTz = startOfDayInTz.subtract(Duration.Days(1));
|
package/dist/date-range.vo.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
2
2
|
export declare const DateRangeError: {
|
|
3
3
|
readonly Invalid: "date.range.invalid";
|
|
4
4
|
};
|
|
5
5
|
export declare class DateRange {
|
|
6
6
|
private readonly start;
|
|
7
7
|
private readonly end;
|
|
8
|
-
constructor(start:
|
|
9
|
-
getStart():
|
|
10
|
-
getEnd():
|
|
11
|
-
toRange(): [
|
|
12
|
-
contains(timestamp:
|
|
8
|
+
constructor(start: Timestamp, end: Timestamp);
|
|
9
|
+
getStart(): Timestamp;
|
|
10
|
+
getEnd(): Timestamp;
|
|
11
|
+
toRange(): [Timestamp, Timestamp];
|
|
12
|
+
contains(timestamp: Timestamp): boolean;
|
|
13
13
|
equals(other: DateRange): boolean;
|
|
14
14
|
toJSON(): {
|
|
15
15
|
start: number;
|
package/dist/day.vo.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
2
|
import { type DayIsoIdType } from "./day-iso-id.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
export declare class Day extends DateRange {
|
|
5
|
-
static fromTimestamp(timestamp:
|
|
6
|
-
static
|
|
6
|
+
static fromTimestamp(timestamp: Timestamp): Day;
|
|
7
|
+
static fromTimestampValue(timestamp: TimestampValueType): Day;
|
|
8
|
+
static fromNow(now: Timestamp): Day;
|
|
7
9
|
static fromIsoId(isoId: DayIsoIdType): Day;
|
|
8
10
|
toIsoId(): DayIsoIdType;
|
|
9
11
|
previous(): Day;
|
package/dist/day.vo.js
CHANGED
|
@@ -2,20 +2,23 @@ import { formatISO } from "date-fns";
|
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { DayIsoId } from "./day-iso-id.vo";
|
|
4
4
|
import { Duration } from "./duration.service";
|
|
5
|
-
import {
|
|
5
|
+
import { Timestamp } from "./timestamp.vo";
|
|
6
6
|
export class Day extends DateRange {
|
|
7
7
|
static fromTimestamp(timestamp) {
|
|
8
8
|
const date = new Date(timestamp.ms);
|
|
9
|
-
const startUtc =
|
|
9
|
+
const startUtc = Timestamp.fromNumber(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
10
10
|
const endUtc = startUtc.add(Duration.Days(1)).subtract(Duration.Ms(1));
|
|
11
11
|
return new Day(startUtc, endUtc);
|
|
12
12
|
}
|
|
13
|
+
static fromTimestampValue(timestamp) {
|
|
14
|
+
return Day.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
15
|
+
}
|
|
13
16
|
static fromNow(now) {
|
|
14
17
|
return Day.fromTimestamp(now);
|
|
15
18
|
}
|
|
16
19
|
static fromIsoId(isoId) {
|
|
17
20
|
const [year, month, day] = DayIsoId.parse(isoId).split("-").map(Number);
|
|
18
|
-
const startUtc =
|
|
21
|
+
const startUtc = Timestamp.fromNumber(Date.UTC(year, month - 1, day));
|
|
19
22
|
const endUtc = startUtc.add(Duration.Days(1)).subtract(Duration.Ms(1));
|
|
20
23
|
return new Day(startUtc, endUtc);
|
|
21
24
|
}
|
package/dist/hour.vo.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { type HourFormatter } from "./hour-format.service";
|
|
2
2
|
import { type HourSchemaType } from "./hour-schema.vo";
|
|
3
|
-
import
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
export declare class Hour {
|
|
5
6
|
private readonly value;
|
|
6
7
|
static readonly ZERO: Hour;
|
|
7
8
|
static readonly MAX: Hour;
|
|
8
9
|
constructor(candidate: number);
|
|
9
|
-
static
|
|
10
|
+
static fromTimestamp(timestamp: Timestamp): Hour;
|
|
11
|
+
static fromTimestampValue(timestamp: TimestampValueType): Hour;
|
|
10
12
|
get(): HourSchemaType;
|
|
11
13
|
format(formatter: HourFormatter): string;
|
|
12
14
|
equals(another: Hour): boolean;
|
package/dist/hour.vo.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HourFormatters } from "./hour-format.service";
|
|
2
2
|
import { HourSchema } from "./hour-schema.vo";
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
4
|
export class Hour {
|
|
4
5
|
value;
|
|
5
6
|
static ZERO = new Hour(0);
|
|
@@ -7,9 +8,12 @@ export class Hour {
|
|
|
7
8
|
constructor(candidate) {
|
|
8
9
|
this.value = HourSchema.parse(candidate);
|
|
9
10
|
}
|
|
10
|
-
static
|
|
11
|
+
static fromTimestamp(timestamp) {
|
|
11
12
|
return new Hour(new Date(timestamp.ms).getUTCHours());
|
|
12
13
|
}
|
|
14
|
+
static fromTimestampValue(timestamp) {
|
|
15
|
+
return Hour.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
16
|
+
}
|
|
13
17
|
get() {
|
|
14
18
|
return this.value;
|
|
15
19
|
}
|
package/dist/minute.vo.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type MinuteSchemaType } from "./minute-schema.vo";
|
|
2
|
-
import
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
3
4
|
export declare class Minute {
|
|
4
5
|
private readonly value;
|
|
5
6
|
static readonly ZERO: Minute;
|
|
6
7
|
static readonly MAX: Minute;
|
|
7
8
|
constructor(candidate: number);
|
|
8
|
-
static
|
|
9
|
+
static fromTimestamp(timestamp: Timestamp): Minute;
|
|
10
|
+
static fromTimestampValue(timestamp: TimestampValueType): Minute;
|
|
9
11
|
get(): MinuteSchemaType;
|
|
10
12
|
equals(another: Minute): boolean;
|
|
11
13
|
isAfter(another: Minute): boolean;
|
package/dist/minute.vo.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MinuteSchema } from "./minute-schema.vo";
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
2
3
|
export class Minute {
|
|
3
4
|
value;
|
|
4
5
|
static ZERO = new Minute(0);
|
|
@@ -6,9 +7,12 @@ export class Minute {
|
|
|
6
7
|
constructor(candidate) {
|
|
7
8
|
this.value = MinuteSchema.parse(candidate);
|
|
8
9
|
}
|
|
9
|
-
static
|
|
10
|
+
static fromTimestamp(timestamp) {
|
|
10
11
|
return new Minute(new Date(timestamp.ms).getUTCMinutes());
|
|
11
12
|
}
|
|
13
|
+
static fromTimestampValue(timestamp) {
|
|
14
|
+
return Minute.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
15
|
+
}
|
|
12
16
|
get() {
|
|
13
17
|
return this.value;
|
|
14
18
|
}
|
package/dist/month.vo.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
2
|
import { type MonthIsoIdType } from "./month-iso-id.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
export declare class Month extends DateRange {
|
|
5
|
-
static fromTimestamp(timestamp:
|
|
6
|
-
static
|
|
6
|
+
static fromTimestamp(timestamp: Timestamp): Month;
|
|
7
|
+
static fromTimestampValue(timestamp: TimestampValueType): Month;
|
|
8
|
+
static fromNow(now: Timestamp): Month;
|
|
7
9
|
static fromIsoId(iso: MonthIsoIdType): Month;
|
|
8
10
|
toIsoId(): MonthIsoIdType;
|
|
9
11
|
previous(): Month;
|
package/dist/month.vo.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { endOfMonth, format, getMonth, setMonth, startOfMonth } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { MonthIsoId } from "./month-iso-id.vo";
|
|
4
|
-
import {
|
|
4
|
+
import { Timestamp } from "./timestamp.vo";
|
|
5
5
|
export class Month extends DateRange {
|
|
6
6
|
static fromTimestamp(timestamp) {
|
|
7
|
-
const start =
|
|
8
|
-
const end =
|
|
7
|
+
const start = Timestamp.fromNumber(startOfMonth(timestamp.ms).getTime());
|
|
8
|
+
const end = Timestamp.fromNumber(endOfMonth(timestamp.ms).getTime());
|
|
9
9
|
return new Month(start, end);
|
|
10
10
|
}
|
|
11
|
+
static fromTimestampValue(timestamp) {
|
|
12
|
+
return Month.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
13
|
+
}
|
|
11
14
|
static fromNow(now) {
|
|
12
15
|
return Month.fromTimestamp(now);
|
|
13
16
|
}
|
|
14
17
|
static fromIsoId(iso) {
|
|
15
18
|
const [year, month] = MonthIsoId.parse(iso).split("-").map(Number);
|
|
16
19
|
const reference = setMonth(Date.UTC(year), month - 1).getTime();
|
|
17
|
-
return Month.fromTimestamp(
|
|
20
|
+
return Month.fromTimestamp(Timestamp.fromNumber(reference));
|
|
18
21
|
}
|
|
19
22
|
toIsoId() {
|
|
20
23
|
return MonthIsoId.parse(format(this.getStart().ms, "yyyy-MM"));
|
|
@@ -27,7 +30,7 @@ export class Month extends DateRange {
|
|
|
27
30
|
}
|
|
28
31
|
shift(count) {
|
|
29
32
|
const shifted = setMonth(this.getStart().ms, getMonth(this.getStart().ms) + count).getTime();
|
|
30
|
-
return Month.fromTimestamp(
|
|
33
|
+
return Month.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
31
34
|
}
|
|
32
35
|
toString() {
|
|
33
36
|
return this.toIsoId();
|
package/dist/quarter.vo.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
2
|
import { type QuarterIsoIdType } from "./quarter-iso-id.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
export declare class Quarter extends DateRange {
|
|
5
|
-
static fromTimestamp(timestamp:
|
|
6
|
-
static
|
|
6
|
+
static fromTimestamp(timestamp: Timestamp): Quarter;
|
|
7
|
+
static fromTimestampValue(timestamp: TimestampValueType): Quarter;
|
|
8
|
+
static fromNow(now: Timestamp): Quarter;
|
|
7
9
|
static fromIsoId(isoId: QuarterIsoIdType): Quarter;
|
|
8
10
|
toIsoId(): QuarterIsoIdType;
|
|
9
11
|
toString(): string;
|
package/dist/quarter.vo.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { endOfQuarter, getQuarter, getYear, setQuarter, startOfQuarter } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { QuarterIsoId } from "./quarter-iso-id.vo";
|
|
4
|
-
import {
|
|
4
|
+
import { Timestamp } from "./timestamp.vo";
|
|
5
5
|
export class Quarter extends DateRange {
|
|
6
6
|
static fromTimestamp(timestamp) {
|
|
7
|
-
const start =
|
|
8
|
-
const end =
|
|
7
|
+
const start = Timestamp.fromNumber(startOfQuarter(timestamp.ms).getTime());
|
|
8
|
+
const end = Timestamp.fromNumber(endOfQuarter(timestamp.ms).getTime());
|
|
9
9
|
return new Quarter(start, end);
|
|
10
10
|
}
|
|
11
|
+
static fromTimestampValue(timestamp) {
|
|
12
|
+
return Quarter.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
13
|
+
}
|
|
11
14
|
static fromNow(now) {
|
|
12
15
|
return Quarter.fromTimestamp(now);
|
|
13
16
|
}
|
|
14
17
|
static fromIsoId(isoId) {
|
|
15
18
|
const [year, quarter] = QuarterIsoId.parse(isoId).split("-Q").map(Number);
|
|
16
19
|
const reference = setQuarter(Date.UTC(year), quarter).getTime();
|
|
17
|
-
return Quarter.fromTimestamp(
|
|
20
|
+
return Quarter.fromTimestamp(Timestamp.fromNumber(reference));
|
|
18
21
|
}
|
|
19
22
|
toIsoId() {
|
|
20
23
|
const year = getYear(this.getStart().ms);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Duration } from "./duration.service";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
3
3
|
type RateLimiterResultSuccessType = {
|
|
4
4
|
allowed: true;
|
|
5
5
|
};
|
|
@@ -12,6 +12,6 @@ export declare class RateLimiter {
|
|
|
12
12
|
private readonly duration;
|
|
13
13
|
private lastInvocation;
|
|
14
14
|
constructor(duration: Duration);
|
|
15
|
-
verify(now:
|
|
15
|
+
verify(now: Timestamp): RateLimiterResultType;
|
|
16
16
|
}
|
|
17
17
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
2
2
|
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
3
3
|
import type { Falsy } from "./ts-utils";
|
|
4
4
|
type RelativeDateType = {
|
|
@@ -6,8 +6,8 @@ type RelativeDateType = {
|
|
|
6
6
|
relative: string;
|
|
7
7
|
};
|
|
8
8
|
export declare class RelativeDate {
|
|
9
|
-
static truthy(timestamp:
|
|
10
|
-
static falsy(timestamp: Falsy<
|
|
9
|
+
static truthy(timestamp: Timestamp): RelativeDateType;
|
|
10
|
+
static falsy(timestamp: Falsy<Timestamp>): RelativeDateType | null;
|
|
11
11
|
private static _format;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Duration } from "./duration.service";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
3
|
export declare const StopwatchError: {
|
|
4
4
|
readonly AlreadyStopped: "stopwatch.already.stopped";
|
|
5
5
|
};
|
|
@@ -7,6 +7,6 @@ export type StopwatchResultType = Duration;
|
|
|
7
7
|
export declare class Stopwatch {
|
|
8
8
|
private readonly start;
|
|
9
9
|
private state;
|
|
10
|
-
constructor(start:
|
|
10
|
+
constructor(start: Timestamp);
|
|
11
11
|
stop(): StopwatchResultType;
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Timestamp } from "./timestamp.vo";
|
|
2
2
|
export const StopwatchError = { AlreadyStopped: "stopwatch.already.stopped" };
|
|
3
3
|
var StopwatchState;
|
|
4
4
|
(function (StopwatchState) {
|
|
@@ -15,6 +15,6 @@ export class Stopwatch {
|
|
|
15
15
|
if (this.state === StopwatchState.stopped)
|
|
16
16
|
throw new Error(StopwatchError.AlreadyStopped);
|
|
17
17
|
this.state = StopwatchState.stopped;
|
|
18
|
-
return
|
|
18
|
+
return Timestamp.fromNumber(Date.now()).difference(this.start);
|
|
19
19
|
}
|
|
20
20
|
}
|
package/dist/timestamp.vo.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { Duration } from "./duration.service";
|
|
2
2
|
import { type TimestampValueType } from "./timestamp-value.vo";
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class Timestamp {
|
|
4
4
|
private readonly value;
|
|
5
5
|
constructor(value: TimestampValueType);
|
|
6
|
-
static fromValue(value: TimestampValueType):
|
|
7
|
-
static fromNumber(value: number):
|
|
8
|
-
add(duration: Duration):
|
|
9
|
-
subtract(duration: Duration):
|
|
10
|
-
difference(another:
|
|
11
|
-
isBefore(another:
|
|
12
|
-
isBeforeOrEqual(another:
|
|
13
|
-
isAfter(another:
|
|
14
|
-
isAfterOrEqual(another:
|
|
15
|
-
equals(another:
|
|
6
|
+
static fromValue(value: TimestampValueType): Timestamp;
|
|
7
|
+
static fromNumber(value: number): Timestamp;
|
|
8
|
+
add(duration: Duration): Timestamp;
|
|
9
|
+
subtract(duration: Duration): Timestamp;
|
|
10
|
+
difference(another: Timestamp): Duration;
|
|
11
|
+
isBefore(another: Timestamp): boolean;
|
|
12
|
+
isBeforeOrEqual(another: Timestamp): boolean;
|
|
13
|
+
isAfter(another: Timestamp): boolean;
|
|
14
|
+
isAfterOrEqual(another: Timestamp): boolean;
|
|
15
|
+
equals(another: Timestamp): boolean;
|
|
16
16
|
get ms(): TimestampValueType;
|
|
17
17
|
toJSON(): TimestampValueType;
|
|
18
18
|
toString(): string;
|
package/dist/timestamp.vo.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { Duration } from "./duration.service";
|
|
2
2
|
import { TimestampValue } from "./timestamp-value.vo";
|
|
3
|
-
export class
|
|
3
|
+
export class Timestamp {
|
|
4
4
|
value;
|
|
5
5
|
constructor(value) {
|
|
6
6
|
this.value = value;
|
|
7
7
|
}
|
|
8
8
|
static fromValue(value) {
|
|
9
|
-
return new
|
|
9
|
+
return new Timestamp(value);
|
|
10
10
|
}
|
|
11
11
|
static fromNumber(value) {
|
|
12
|
-
return new
|
|
12
|
+
return new Timestamp(TimestampValue.parse(value));
|
|
13
13
|
}
|
|
14
14
|
add(duration) {
|
|
15
|
-
return
|
|
15
|
+
return Timestamp.fromNumber(this.value + duration.ms);
|
|
16
16
|
}
|
|
17
17
|
subtract(duration) {
|
|
18
|
-
return
|
|
18
|
+
return Timestamp.fromNumber(this.value - duration.ms);
|
|
19
19
|
}
|
|
20
20
|
difference(another) {
|
|
21
21
|
return Duration.Ms(this.value - another.value);
|
package/dist/week.vo.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
3
4
|
import { type WeekIsoIdType } from "./week-iso-id.vo";
|
|
4
5
|
export declare class Week extends DateRange {
|
|
5
|
-
static fromTimestamp(timestamp:
|
|
6
|
-
static
|
|
6
|
+
static fromTimestamp(timestamp: Timestamp): Week;
|
|
7
|
+
static fromTimestampValue(timestamp: TimestampValueType): Week;
|
|
8
|
+
static fromNow(now: Timestamp): Week;
|
|
7
9
|
static fromIsoId(isoId: WeekIsoIdType): Week;
|
|
8
10
|
toIsoId(): WeekIsoIdType;
|
|
9
11
|
previous(): Week;
|
package/dist/week.vo.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { addWeeks, endOfISOWeek, getISOWeek, getISOWeekYear, setISOWeek, startOfISOWeek } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
4
|
import { WeekIsoId } from "./week-iso-id.vo";
|
|
5
5
|
export class Week extends DateRange {
|
|
6
6
|
static fromTimestamp(timestamp) {
|
|
7
|
-
const start =
|
|
8
|
-
const end =
|
|
7
|
+
const start = Timestamp.fromNumber(startOfISOWeek(timestamp.ms).getTime());
|
|
8
|
+
const end = Timestamp.fromNumber(endOfISOWeek(timestamp.ms).getTime());
|
|
9
9
|
return new Week(start, end);
|
|
10
10
|
}
|
|
11
|
+
static fromTimestampValue(timestamp) {
|
|
12
|
+
return Week.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
13
|
+
}
|
|
11
14
|
static fromNow(now) {
|
|
12
15
|
return Week.fromTimestamp(now);
|
|
13
16
|
}
|
|
@@ -15,7 +18,7 @@ export class Week extends DateRange {
|
|
|
15
18
|
const [year, week] = WeekIsoId.parse(isoId).split("-W").map(Number);
|
|
16
19
|
// ISO-8601 rule: Jan 4 is always in week 01 of the ISO week-year.
|
|
17
20
|
const reference = setISOWeek(Date.UTC(year, 0, 4), week).getTime();
|
|
18
|
-
return Week.fromTimestamp(
|
|
21
|
+
return Week.fromTimestamp(Timestamp.fromNumber(reference));
|
|
19
22
|
}
|
|
20
23
|
toIsoId() {
|
|
21
24
|
const year = getISOWeekYear(this.getStart().ms);
|
|
@@ -30,7 +33,7 @@ export class Week extends DateRange {
|
|
|
30
33
|
}
|
|
31
34
|
shift(count) {
|
|
32
35
|
const shifted = addWeeks(this.getStart().ms, count).getTime();
|
|
33
|
-
return Week.fromTimestamp(
|
|
36
|
+
return Week.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
34
37
|
}
|
|
35
38
|
toString() {
|
|
36
39
|
return this.toIsoId();
|
package/dist/weekday.vo.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Timestamp } from "./timestamp.vo";
|
|
2
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
2
3
|
export type WeekdayFormatter = (value: Weekday["value"]) => string;
|
|
3
4
|
export declare enum WeekdayFormatterEnum {
|
|
4
5
|
FULL = "FULL",// "Sunday"
|
|
@@ -19,7 +20,8 @@ export declare class Weekday {
|
|
|
19
20
|
static readonly FRIDAY: Weekday;
|
|
20
21
|
static readonly SATURDAY: Weekday;
|
|
21
22
|
constructor(candidate: number, formatter?: WeekdayFormatter);
|
|
22
|
-
static
|
|
23
|
+
static fromTimestamp(timestamp: Timestamp, formatter?: WeekdayFormatter): Weekday;
|
|
24
|
+
static fromTimestampValue(timestamp: TimestampValueType): Weekday;
|
|
23
25
|
get(): number;
|
|
24
26
|
format(): string;
|
|
25
27
|
toString(): string;
|
package/dist/weekday.vo.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Timestamp } from "./timestamp.vo";
|
|
1
2
|
export var WeekdayFormatterEnum;
|
|
2
3
|
(function (WeekdayFormatterEnum) {
|
|
3
4
|
WeekdayFormatterEnum["FULL"] = "FULL";
|
|
@@ -40,10 +41,13 @@ export class Weekday {
|
|
|
40
41
|
this.value = candidate;
|
|
41
42
|
this.formatter = formatter ?? WeekdayFormatters.FULL;
|
|
42
43
|
}
|
|
43
|
-
static
|
|
44
|
+
static fromTimestamp(timestamp, formatter) {
|
|
44
45
|
const dayZeroBased = new Date(timestamp.ms).getUTCDay(); // 0..6
|
|
45
46
|
return new Weekday(dayZeroBased, formatter);
|
|
46
47
|
}
|
|
48
|
+
static fromTimestampValue(timestamp) {
|
|
49
|
+
return Weekday.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
50
|
+
}
|
|
47
51
|
get() {
|
|
48
52
|
return this.value;
|
|
49
53
|
}
|
package/dist/year.vo.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DateRange } from "./date-range.vo";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
3
4
|
import { type YearIsoIdType } from "./year-iso-id.vo";
|
|
4
5
|
export declare class Year extends DateRange {
|
|
5
|
-
static fromTimestamp(timestamp:
|
|
6
|
-
static
|
|
6
|
+
static fromTimestamp(timestamp: Timestamp): Year;
|
|
7
|
+
static fromTimestampValue(timestamp: TimestampValueType): Year;
|
|
8
|
+
static fromNow(now: Timestamp): Year;
|
|
7
9
|
static fromNumber(candidate: number): Year;
|
|
8
10
|
static fromIsoId(isoId: YearIsoIdType): Year;
|
|
9
11
|
toIsoId(): YearIsoIdType;
|
package/dist/year.vo.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { addYears, endOfYear, getYear, startOfYear } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
4
|
import { YearIsoId } from "./year-iso-id.vo";
|
|
5
5
|
export class Year extends DateRange {
|
|
6
6
|
static fromTimestamp(timestamp) {
|
|
7
|
-
const start =
|
|
8
|
-
const end =
|
|
7
|
+
const start = Timestamp.fromNumber(startOfYear(timestamp.ms).getTime());
|
|
8
|
+
const end = Timestamp.fromNumber(endOfYear(timestamp.ms).getTime());
|
|
9
9
|
return new Year(start, end);
|
|
10
10
|
}
|
|
11
|
+
static fromTimestampValue(timestamp) {
|
|
12
|
+
return Year.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
13
|
+
}
|
|
11
14
|
static fromNow(now) {
|
|
12
15
|
return Year.fromTimestamp(now);
|
|
13
16
|
}
|
|
@@ -16,7 +19,7 @@ export class Year extends DateRange {
|
|
|
16
19
|
}
|
|
17
20
|
static fromIsoId(isoId) {
|
|
18
21
|
const reference = Date.UTC(Number(isoId));
|
|
19
|
-
return Year.fromTimestamp(
|
|
22
|
+
return Year.fromTimestamp(Timestamp.fromNumber(reference));
|
|
20
23
|
}
|
|
21
24
|
toIsoId() {
|
|
22
25
|
return YearIsoId.parse(String(getYear(this.getStart().ms)));
|
|
@@ -33,7 +36,7 @@ export class Year extends DateRange {
|
|
|
33
36
|
}
|
|
34
37
|
shift(count) {
|
|
35
38
|
const shifted = addYears(this.getStart().ms, count).getTime();
|
|
36
|
-
return Year.fromTimestamp(
|
|
39
|
+
return Year.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
37
40
|
}
|
|
38
41
|
toString() {
|
|
39
42
|
return this.toIsoId();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bgord/tools",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bartosz Gordon",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@types/bun": "1.3.1",
|
|
28
28
|
"@types/mime-types": "3.0.1",
|
|
29
29
|
"cspell": "9.2.2",
|
|
30
|
-
"knip": "5.
|
|
30
|
+
"knip": "5.67.0",
|
|
31
31
|
"lefthook": "2.0.2",
|
|
32
32
|
"only-allow": "1.2.1",
|
|
33
33
|
"shellcheck": "4.1.0",
|
package/src/age.vo.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { differenceInYears } from "date-fns";
|
|
2
2
|
import { AgeYears, AgeYearsConstraints, type AgeYearsType } from "./age-years.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
4
|
|
|
5
5
|
export const AgeError = { FutureBirthdate: "age.future.birthdate" } as const;
|
|
6
6
|
|
|
@@ -14,13 +14,13 @@ export class Age {
|
|
|
14
14
|
return new Age(AgeYears.parse(candidate));
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
static
|
|
17
|
+
static fromBirthdateTimestamp(params: { birthdate: Timestamp; now: Timestamp }): Age {
|
|
18
18
|
if (params.birthdate.isAfter(params.now)) throw new Error(AgeError.FutureBirthdate);
|
|
19
19
|
return Age.fromValue(differenceInYears(params.now.ms, params.birthdate.ms));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
static fromBirthdate(candidate: { birthdate: string; now:
|
|
23
|
-
const birthdate =
|
|
22
|
+
static fromBirthdate(candidate: { birthdate: string; now: Timestamp }): Age {
|
|
23
|
+
const birthdate = Timestamp.fromNumber(new Date(candidate.birthdate).getTime());
|
|
24
24
|
|
|
25
25
|
if (birthdate.isAfter(candidate.now)) throw new Error(AgeError.FutureBirthdate);
|
|
26
26
|
return Age.fromValue(differenceInYears(candidate.now.ms, birthdate.ms));
|
package/src/clock.vo.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Hour } from "./hour.vo";
|
|
|
3
3
|
import type { HourSchemaType } from "./hour-schema.vo";
|
|
4
4
|
import { Minute } from "./minute.vo";
|
|
5
5
|
import type { MinuteSchemaType } from "./minute-schema.vo";
|
|
6
|
-
import type {
|
|
6
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
7
7
|
|
|
8
8
|
export class Clock {
|
|
9
9
|
private readonly formatter: ClockFormatter;
|
|
@@ -16,9 +16,9 @@ export class Clock {
|
|
|
16
16
|
this.formatter = formatter ?? ClockFormatters.TWENTY_FOUR_HOURS;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
static
|
|
20
|
-
const hour = Hour.
|
|
21
|
-
const minute = Minute.
|
|
19
|
+
static fromTimestamp(timestamp: Timestamp, formatter?: ClockFormatter): Clock {
|
|
20
|
+
const hour = Hour.fromTimestamp(timestamp);
|
|
21
|
+
const minute = Minute.fromTimestamp(timestamp);
|
|
22
22
|
|
|
23
23
|
return new Clock(hour, minute, formatter);
|
|
24
24
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Duration } from "./duration.service";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
3
|
|
|
4
|
-
type GetStartOfDayTsInTzConfigType = { now:
|
|
4
|
+
type GetStartOfDayTsInTzConfigType = { now: Timestamp; timeZoneOffset: Duration };
|
|
5
5
|
|
|
6
6
|
export class DateCalculator {
|
|
7
|
-
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType):
|
|
7
|
+
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType): Timestamp {
|
|
8
8
|
const dayMs = Duration.Days(1).ms;
|
|
9
9
|
|
|
10
|
-
const utcMidnightOfNow =
|
|
10
|
+
const utcMidnightOfNow = Timestamp.fromNumber(Math.floor(config.now.ms / dayMs) * dayMs);
|
|
11
11
|
|
|
12
12
|
let startOfDayInTz = utcMidnightOfNow.add(config.timeZoneOffset);
|
|
13
13
|
|
package/src/date-range.vo.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
2
2
|
|
|
3
3
|
export const DateRangeError = { Invalid: "date.range.invalid" } as const;
|
|
4
4
|
|
|
5
5
|
export class DateRange {
|
|
6
6
|
constructor(
|
|
7
|
-
private readonly start:
|
|
8
|
-
private readonly end:
|
|
7
|
+
private readonly start: Timestamp,
|
|
8
|
+
private readonly end: Timestamp,
|
|
9
9
|
) {
|
|
10
10
|
if (start.isAfter(end)) throw new Error(DateRangeError.Invalid);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
getStart():
|
|
13
|
+
getStart(): Timestamp {
|
|
14
14
|
return this.start;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
getEnd():
|
|
17
|
+
getEnd(): Timestamp {
|
|
18
18
|
return this.end;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
toRange(): [
|
|
21
|
+
toRange(): [Timestamp, Timestamp] {
|
|
22
22
|
return [this.start, this.end];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
contains(timestamp:
|
|
25
|
+
contains(timestamp: Timestamp): boolean {
|
|
26
26
|
return timestamp.isAfterOrEqual(this.start) && timestamp.isBeforeOrEqual(this.end);
|
|
27
27
|
}
|
|
28
28
|
|
package/src/day.vo.ts
CHANGED
|
@@ -2,13 +2,14 @@ import { formatISO } from "date-fns";
|
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { DayIsoId, type DayIsoIdType } from "./day-iso-id.vo";
|
|
4
4
|
import { Duration } from "./duration.service";
|
|
5
|
-
import {
|
|
5
|
+
import { Timestamp } from "./timestamp.vo";
|
|
6
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
6
7
|
|
|
7
8
|
export class Day extends DateRange {
|
|
8
|
-
static fromTimestamp(timestamp:
|
|
9
|
+
static fromTimestamp(timestamp: Timestamp): Day {
|
|
9
10
|
const date = new Date(timestamp.ms);
|
|
10
11
|
|
|
11
|
-
const startUtc =
|
|
12
|
+
const startUtc = Timestamp.fromNumber(
|
|
12
13
|
Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
|
|
13
14
|
);
|
|
14
15
|
const endUtc = startUtc.add(Duration.Days(1)).subtract(Duration.Ms(1));
|
|
@@ -16,14 +17,18 @@ export class Day extends DateRange {
|
|
|
16
17
|
return new Day(startUtc, endUtc);
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
static
|
|
20
|
+
static fromTimestampValue(timestamp: TimestampValueType): Day {
|
|
21
|
+
return Day.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static fromNow(now: Timestamp): Day {
|
|
20
25
|
return Day.fromTimestamp(now);
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
static fromIsoId(isoId: DayIsoIdType): Day {
|
|
24
29
|
const [year, month, day] = DayIsoId.parse(isoId).split("-").map(Number);
|
|
25
30
|
|
|
26
|
-
const startUtc =
|
|
31
|
+
const startUtc = Timestamp.fromNumber(Date.UTC(year, month - 1, day));
|
|
27
32
|
const endUtc = startUtc.add(Duration.Days(1)).subtract(Duration.Ms(1));
|
|
28
33
|
|
|
29
34
|
return new Day(startUtc, endUtc);
|
package/src/hour.vo.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type HourFormatter, HourFormatters } from "./hour-format.service";
|
|
2
2
|
import { HourSchema, type HourSchemaType } from "./hour-schema.vo";
|
|
3
|
-
import
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
|
|
5
6
|
export class Hour {
|
|
6
7
|
private readonly value: HourSchemaType;
|
|
@@ -12,10 +13,14 @@ export class Hour {
|
|
|
12
13
|
this.value = HourSchema.parse(candidate);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
static
|
|
16
|
+
static fromTimestamp(timestamp: Timestamp): Hour {
|
|
16
17
|
return new Hour(new Date(timestamp.ms).getUTCHours());
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
static fromTimestampValue(timestamp: TimestampValueType): Hour {
|
|
21
|
+
return Hour.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
22
|
+
}
|
|
23
|
+
|
|
19
24
|
get(): HourSchemaType {
|
|
20
25
|
return this.value;
|
|
21
26
|
}
|
package/src/minute.vo.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MinuteSchema, type MinuteSchemaType } from "./minute-schema.vo";
|
|
2
|
-
import
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
3
4
|
|
|
4
5
|
export class Minute {
|
|
5
6
|
private readonly value: MinuteSchemaType;
|
|
@@ -11,10 +12,14 @@ export class Minute {
|
|
|
11
12
|
this.value = MinuteSchema.parse(candidate);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
static
|
|
15
|
+
static fromTimestamp(timestamp: Timestamp): Minute {
|
|
15
16
|
return new Minute(new Date(timestamp.ms).getUTCMinutes());
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
static fromTimestampValue(timestamp: TimestampValueType): Minute {
|
|
20
|
+
return Minute.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
get(): MinuteSchemaType {
|
|
19
24
|
return this.value;
|
|
20
25
|
}
|
package/src/month.vo.ts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { endOfMonth, format, getMonth, setMonth, startOfMonth } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { MonthIsoId, type MonthIsoIdType } from "./month-iso-id.vo";
|
|
4
|
-
import {
|
|
4
|
+
import { Timestamp } from "./timestamp.vo";
|
|
5
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
5
6
|
|
|
6
7
|
export class Month extends DateRange {
|
|
7
|
-
static fromTimestamp(timestamp:
|
|
8
|
-
const start =
|
|
9
|
-
const end =
|
|
8
|
+
static fromTimestamp(timestamp: Timestamp): Month {
|
|
9
|
+
const start = Timestamp.fromNumber(startOfMonth(timestamp.ms).getTime());
|
|
10
|
+
const end = Timestamp.fromNumber(endOfMonth(timestamp.ms).getTime());
|
|
10
11
|
|
|
11
12
|
return new Month(start, end);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
static
|
|
15
|
+
static fromTimestampValue(timestamp: TimestampValueType): Month {
|
|
16
|
+
return Month.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static fromNow(now: Timestamp): Month {
|
|
15
20
|
return Month.fromTimestamp(now);
|
|
16
21
|
}
|
|
17
22
|
|
|
@@ -20,7 +25,7 @@ export class Month extends DateRange {
|
|
|
20
25
|
|
|
21
26
|
const reference = setMonth(Date.UTC(year), month - 1).getTime();
|
|
22
27
|
|
|
23
|
-
return Month.fromTimestamp(
|
|
28
|
+
return Month.fromTimestamp(Timestamp.fromNumber(reference));
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
toIsoId(): MonthIsoIdType {
|
|
@@ -38,7 +43,7 @@ export class Month extends DateRange {
|
|
|
38
43
|
shift(count: number): Month {
|
|
39
44
|
const shifted = setMonth(this.getStart().ms, getMonth(this.getStart().ms) + count).getTime();
|
|
40
45
|
|
|
41
|
-
return Month.fromTimestamp(
|
|
46
|
+
return Month.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
toString(): string {
|
package/src/quarter.vo.ts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { endOfQuarter, getQuarter, getYear, setQuarter, startOfQuarter } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { QuarterIsoId, type QuarterIsoIdType } from "./quarter-iso-id.vo";
|
|
4
|
-
import {
|
|
4
|
+
import { Timestamp } from "./timestamp.vo";
|
|
5
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
5
6
|
|
|
6
7
|
export class Quarter extends DateRange {
|
|
7
|
-
static fromTimestamp(timestamp:
|
|
8
|
-
const start =
|
|
9
|
-
const end =
|
|
8
|
+
static fromTimestamp(timestamp: Timestamp): Quarter {
|
|
9
|
+
const start = Timestamp.fromNumber(startOfQuarter(timestamp.ms).getTime());
|
|
10
|
+
const end = Timestamp.fromNumber(endOfQuarter(timestamp.ms).getTime());
|
|
10
11
|
|
|
11
12
|
return new Quarter(start, end);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
static
|
|
15
|
+
static fromTimestampValue(timestamp: TimestampValueType): Quarter {
|
|
16
|
+
return Quarter.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static fromNow(now: Timestamp): Quarter {
|
|
15
20
|
return Quarter.fromTimestamp(now);
|
|
16
21
|
}
|
|
17
22
|
|
|
@@ -20,7 +25,7 @@ export class Quarter extends DateRange {
|
|
|
20
25
|
|
|
21
26
|
const reference = setQuarter(Date.UTC(year), quarter).getTime();
|
|
22
27
|
|
|
23
|
-
return Quarter.fromTimestamp(
|
|
28
|
+
return Quarter.fromTimestamp(Timestamp.fromNumber(reference));
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
toIsoId(): QuarterIsoIdType {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { Duration } from "./duration.service";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
3
3
|
|
|
4
4
|
type RateLimiterResultSuccessType = { allowed: true };
|
|
5
5
|
type RateLimiterResultErrorType = { allowed: false; remaining: Duration };
|
|
6
6
|
type RateLimiterResultType = RateLimiterResultSuccessType | RateLimiterResultErrorType;
|
|
7
7
|
|
|
8
8
|
export class RateLimiter {
|
|
9
|
-
private lastInvocation:
|
|
9
|
+
private lastInvocation: Timestamp | null = null;
|
|
10
10
|
|
|
11
11
|
constructor(private readonly duration: Duration) {}
|
|
12
12
|
|
|
13
|
-
verify(now:
|
|
13
|
+
verify(now: Timestamp): RateLimiterResultType {
|
|
14
14
|
if (this.lastInvocation == null) {
|
|
15
15
|
this.lastInvocation = now;
|
|
16
16
|
|
package/src/relative-date.vo.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { DateFormatters } from "./date-formatter.service";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Timestamp } from "./timestamp.vo";
|
|
3
3
|
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
4
|
import type { Falsy } from "./ts-utils";
|
|
5
5
|
|
|
6
6
|
type RelativeDateType = { raw: TimestampValueType; relative: string };
|
|
7
7
|
|
|
8
8
|
export class RelativeDate {
|
|
9
|
-
static truthy(timestamp:
|
|
9
|
+
static truthy(timestamp: Timestamp): RelativeDateType {
|
|
10
10
|
return RelativeDate._format(timestamp);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
static falsy(timestamp: Falsy<
|
|
13
|
+
static falsy(timestamp: Falsy<Timestamp>): RelativeDateType | null {
|
|
14
14
|
if (!timestamp) return null;
|
|
15
15
|
return RelativeDate._format(timestamp);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
private static _format(timestamp:
|
|
18
|
+
private static _format(timestamp: Timestamp): RelativeDateType {
|
|
19
19
|
return { raw: timestamp.ms, relative: DateFormatters.relative(timestamp.ms) };
|
|
20
20
|
}
|
|
21
21
|
}
|
package/src/stopwatch.service.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Duration } from "./duration.service";
|
|
2
|
-
import {
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
3
3
|
|
|
4
4
|
export const StopwatchError = { AlreadyStopped: "stopwatch.already.stopped" } as const;
|
|
5
5
|
|
|
@@ -13,13 +13,13 @@ export type StopwatchResultType = Duration;
|
|
|
13
13
|
export class Stopwatch {
|
|
14
14
|
private state: StopwatchState = StopwatchState.started;
|
|
15
15
|
|
|
16
|
-
constructor(private readonly start:
|
|
16
|
+
constructor(private readonly start: Timestamp) {}
|
|
17
17
|
|
|
18
18
|
stop(): StopwatchResultType {
|
|
19
19
|
if (this.state === StopwatchState.stopped) throw new Error(StopwatchError.AlreadyStopped);
|
|
20
20
|
|
|
21
21
|
this.state = StopwatchState.stopped;
|
|
22
22
|
|
|
23
|
-
return
|
|
23
|
+
return Timestamp.fromNumber(Date.now()).difference(this.start);
|
|
24
24
|
}
|
|
25
25
|
}
|
package/src/timestamp.vo.ts
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
import { Duration } from "./duration.service";
|
|
2
2
|
import { TimestampValue, type TimestampValueType } from "./timestamp-value.vo";
|
|
3
3
|
|
|
4
|
-
export class
|
|
4
|
+
export class Timestamp {
|
|
5
5
|
constructor(private readonly value: TimestampValueType) {}
|
|
6
6
|
|
|
7
|
-
static fromValue(value: TimestampValueType):
|
|
8
|
-
return new
|
|
7
|
+
static fromValue(value: TimestampValueType): Timestamp {
|
|
8
|
+
return new Timestamp(value);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
static fromNumber(value: number):
|
|
12
|
-
return new
|
|
11
|
+
static fromNumber(value: number): Timestamp {
|
|
12
|
+
return new Timestamp(TimestampValue.parse(value));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
add(duration: Duration):
|
|
16
|
-
return
|
|
15
|
+
add(duration: Duration): Timestamp {
|
|
16
|
+
return Timestamp.fromNumber(this.value + duration.ms);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
subtract(duration: Duration):
|
|
20
|
-
return
|
|
19
|
+
subtract(duration: Duration): Timestamp {
|
|
20
|
+
return Timestamp.fromNumber(this.value - duration.ms);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
difference(another:
|
|
23
|
+
difference(another: Timestamp): Duration {
|
|
24
24
|
return Duration.Ms(this.value - another.value);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
isBefore(another:
|
|
27
|
+
isBefore(another: Timestamp): boolean {
|
|
28
28
|
return this.value < another.value;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
isBeforeOrEqual(another:
|
|
31
|
+
isBeforeOrEqual(another: Timestamp): boolean {
|
|
32
32
|
return this.value <= another.value;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
isAfter(another:
|
|
35
|
+
isAfter(another: Timestamp): boolean {
|
|
36
36
|
return this.value > another.value;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
isAfterOrEqual(another:
|
|
39
|
+
isAfterOrEqual(another: Timestamp): boolean {
|
|
40
40
|
return this.value >= another.value;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
equals(another:
|
|
43
|
+
equals(another: Timestamp): boolean {
|
|
44
44
|
return this.value === another.value;
|
|
45
45
|
}
|
|
46
46
|
|
package/src/week.vo.ts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { addWeeks, endOfISOWeek, getISOWeek, getISOWeekYear, setISOWeek, startOfISOWeek } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
import { WeekIsoId, type WeekIsoIdType } from "./week-iso-id.vo";
|
|
5
6
|
|
|
6
7
|
export class Week extends DateRange {
|
|
7
|
-
static fromTimestamp(timestamp:
|
|
8
|
-
const start =
|
|
9
|
-
const end =
|
|
8
|
+
static fromTimestamp(timestamp: Timestamp): Week {
|
|
9
|
+
const start = Timestamp.fromNumber(startOfISOWeek(timestamp.ms).getTime());
|
|
10
|
+
const end = Timestamp.fromNumber(endOfISOWeek(timestamp.ms).getTime());
|
|
10
11
|
|
|
11
12
|
return new Week(start, end);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
static
|
|
15
|
+
static fromTimestampValue(timestamp: TimestampValueType): Week {
|
|
16
|
+
return Week.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static fromNow(now: Timestamp): Week {
|
|
15
20
|
return Week.fromTimestamp(now);
|
|
16
21
|
}
|
|
17
22
|
|
|
@@ -21,7 +26,7 @@ export class Week extends DateRange {
|
|
|
21
26
|
// ISO-8601 rule: Jan 4 is always in week 01 of the ISO week-year.
|
|
22
27
|
const reference = setISOWeek(Date.UTC(year, 0, 4), week).getTime();
|
|
23
28
|
|
|
24
|
-
return Week.fromTimestamp(
|
|
29
|
+
return Week.fromTimestamp(Timestamp.fromNumber(reference));
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
toIsoId(): WeekIsoIdType {
|
|
@@ -42,7 +47,7 @@ export class Week extends DateRange {
|
|
|
42
47
|
shift(count: number): Week {
|
|
43
48
|
const shifted = addWeeks(this.getStart().ms, count).getTime();
|
|
44
49
|
|
|
45
|
-
return Week.fromTimestamp(
|
|
50
|
+
return Week.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
toString(): string {
|
package/src/weekday.vo.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Timestamp } from "./timestamp.vo";
|
|
2
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
2
3
|
|
|
3
4
|
export type WeekdayFormatter = (value: Weekday["value"]) => string;
|
|
4
5
|
|
|
@@ -52,11 +53,15 @@ export class Weekday {
|
|
|
52
53
|
this.formatter = formatter ?? WeekdayFormatters.FULL;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
static
|
|
56
|
+
static fromTimestamp(timestamp: Timestamp, formatter?: WeekdayFormatter): Weekday {
|
|
56
57
|
const dayZeroBased = new Date(timestamp.ms).getUTCDay(); // 0..6
|
|
57
58
|
return new Weekday(dayZeroBased, formatter);
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
static fromTimestampValue(timestamp: TimestampValueType): Weekday {
|
|
62
|
+
return Weekday.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
get(): number {
|
|
61
66
|
return this.value;
|
|
62
67
|
}
|
package/src/year.vo.ts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { addYears, endOfYear, getYear, startOfYear } from "date-fns";
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
|
-
import {
|
|
3
|
+
import { Timestamp } from "./timestamp.vo";
|
|
4
|
+
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
4
5
|
import { YearIsoId, type YearIsoIdType } from "./year-iso-id.vo";
|
|
5
6
|
|
|
6
7
|
export class Year extends DateRange {
|
|
7
|
-
static fromTimestamp(timestamp:
|
|
8
|
-
const start =
|
|
9
|
-
const end =
|
|
8
|
+
static fromTimestamp(timestamp: Timestamp): Year {
|
|
9
|
+
const start = Timestamp.fromNumber(startOfYear(timestamp.ms).getTime());
|
|
10
|
+
const end = Timestamp.fromNumber(endOfYear(timestamp.ms).getTime());
|
|
10
11
|
|
|
11
12
|
return new Year(start, end);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
static
|
|
15
|
+
static fromTimestampValue(timestamp: TimestampValueType): Year {
|
|
16
|
+
return Year.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static fromNow(now: Timestamp): Year {
|
|
15
20
|
return Year.fromTimestamp(now);
|
|
16
21
|
}
|
|
17
22
|
|
|
@@ -22,7 +27,7 @@ export class Year extends DateRange {
|
|
|
22
27
|
static fromIsoId(isoId: YearIsoIdType): Year {
|
|
23
28
|
const reference = Date.UTC(Number(isoId));
|
|
24
29
|
|
|
25
|
-
return Year.fromTimestamp(
|
|
30
|
+
return Year.fromTimestamp(Timestamp.fromNumber(reference));
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
toIsoId(): YearIsoIdType {
|
|
@@ -46,7 +51,7 @@ export class Year extends DateRange {
|
|
|
46
51
|
shift(count: number): Year {
|
|
47
52
|
const shifted = addYears(this.getStart().ms, count).getTime();
|
|
48
53
|
|
|
49
|
-
return Year.fromTimestamp(
|
|
54
|
+
return Year.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
toString(): string {
|