@bash-app/bash-common 29.45.0 → 29.47.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.
@@ -1,99 +1,99 @@
1
- import {DeleteObjectCommand, PutObjectCommand, S3Client} from "@aws-sdk/client-s3";
2
- import {getSignedUrl} from "@aws-sdk/s3-request-presigner";
3
- import {DeleteObjectCommandOutput} from "@aws-sdk/client-s3/dist-types/commands";
4
-
5
- const BASE_64_IMAGE_REGEX = /^data:image\/\w+;base64,/;
6
-
7
- export class AwsS3Utils {
8
- static async uploadBase64String(base64Str: string, assetKey: string): Promise<string | undefined> {
9
- const bufferData = Buffer.from(base64Str.replace(BASE_64_IMAGE_REGEX, ""), 'base64');
10
- const blobData = new Blob([bufferData]);
11
- return AwsS3Utils.uploadFile(blobData, assetKey, 'image/jpeg');
12
- }
13
-
14
- static async uploadFile(file: Blob, assetKey: string, mimetype: string): Promise<string | undefined> {
15
- const preSignedUrl = await AwsS3Utils.createPreSignedUrl(assetKey, mimetype);
16
- const assetUrl = AwsS3Utils.createUrlFromAssetKey(assetKey);
17
- const uploadSuccessful = await AwsS3Utils.uploadFileViaPreSignedUrl(file, preSignedUrl, mimetype);
18
- if (uploadSuccessful) {
19
- return assetUrl;
20
- }
21
- }
22
-
23
- static async uploadFileViaPreSignedUrl(file: Blob,
24
- preSignedUrl: string | undefined,
25
- mimetype: string): Promise<boolean> {
26
- try {
27
- if (!file) {
28
- throw new Error('The file data buffer was undefined; no data to upload.');
29
- }
30
- if (!preSignedUrl) {
31
- throw new Error('The pre-signed url for uploading the file was undefined');
32
- }
33
- const res = await fetch(preSignedUrl, {
34
- method: 'PUT',
35
- headers: {
36
- 'Content-Type': mimetype
37
- },
38
- body: file
39
- });
40
-
41
- if (!res.ok) {
42
- throw new Error(`Response was not ok when uploading media file.\nStatus, text: ${res.status}, ${res.statusText}`);
43
- }
44
- return true;
45
- }
46
- catch (e) {
47
- console.error(`Error when uploading file to: ${preSignedUrl}\n${e}`);
48
- return false;
49
- }
50
- }
51
-
52
- static createUrlFromAssetKey(assetKey: string): string {
53
- if (!assetKey) {
54
- throw new Error(`Cannot create a url with an assetKey that is undefined`);
55
- }
56
- return `https://${process.env.CLOUDFRONT_ASSETS_URL}/${assetKey}`;
57
- }
58
-
59
- static async createPreSignedUrl(key: string | undefined, mimetype: string | undefined): Promise<string> {
60
- if (!key || !mimetype) {
61
- throw new Error(`Cannot create a pre-signed url without a key or a mimetype`);
62
- }
63
- const client = new S3Client({
64
- credentials: {
65
- accessKeyId: String(process.env.AWS_S3_ACCESS_KEY_ID),
66
- secretAccessKey: String(process.env.AWS_S3_SECRET_ACCESS_KEY),
67
- },
68
- region: String(process.env.AWS_S3_REGION),
69
- });
70
- const command = new PutObjectCommand({
71
- Bucket: String(process.env.AWS_S3_ASSETS_BUCKET_NAME),
72
- Key: key,
73
- ContentType: mimetype
74
- });
75
- return getSignedUrl(client, command, {
76
- expiresIn: 3600,
77
- });
78
- }
79
-
80
- static async deleteFile(key: string): Promise<DeleteObjectCommandOutput | undefined> {
81
- try {
82
- const command = new DeleteObjectCommand({
83
- Bucket: String(process.env.AWS_S3_BUCKET_NAME),
84
- Key: key,
85
- });
86
- const client = new S3Client({
87
- credentials: {
88
- accessKeyId: String(process.env.AWS_S3_ACCESS_KEY_ID),
89
- secretAccessKey: String(process.env.AWS_S3_SECRET_ACCESS_KEY),
90
- },
91
- region: String(process.env.AWS_S3_REGION),
92
- });
93
- return client.send(command);
94
- }
95
- catch (e: any) {
96
- console.error(e);
97
- }
98
- }
99
- }
1
+ import {DeleteObjectCommand, PutObjectCommand, S3Client} from "@aws-sdk/client-s3";
2
+ import {getSignedUrl} from "@aws-sdk/s3-request-presigner";
3
+ import {DeleteObjectCommandOutput} from "@aws-sdk/client-s3/dist-types/commands";
4
+
5
+ const BASE_64_IMAGE_REGEX = /^data:image\/\w+;base64,/;
6
+
7
+ export class AwsS3Utils {
8
+ static async uploadBase64String(base64Str: string, assetKey: string): Promise<string | undefined> {
9
+ const bufferData = Buffer.from(base64Str.replace(BASE_64_IMAGE_REGEX, ""), 'base64');
10
+ const blobData = new Blob([bufferData]);
11
+ return AwsS3Utils.uploadFile(blobData, assetKey, 'image/jpeg');
12
+ }
13
+
14
+ static async uploadFile(file: Blob, assetKey: string, mimetype: string): Promise<string | undefined> {
15
+ const preSignedUrl = await AwsS3Utils.createPreSignedUrl(assetKey, mimetype);
16
+ const assetUrl = AwsS3Utils.createUrlFromAssetKey(assetKey);
17
+ const uploadSuccessful = await AwsS3Utils.uploadFileViaPreSignedUrl(file, preSignedUrl, mimetype);
18
+ if (uploadSuccessful) {
19
+ return assetUrl;
20
+ }
21
+ }
22
+
23
+ static async uploadFileViaPreSignedUrl(file: Blob,
24
+ preSignedUrl: string | undefined,
25
+ mimetype: string): Promise<boolean> {
26
+ try {
27
+ if (!file) {
28
+ throw new Error('The file data buffer was undefined; no data to upload.');
29
+ }
30
+ if (!preSignedUrl) {
31
+ throw new Error('The pre-signed url for uploading the file was undefined');
32
+ }
33
+ const res = await fetch(preSignedUrl, {
34
+ method: 'PUT',
35
+ headers: {
36
+ 'Content-Type': mimetype
37
+ },
38
+ body: file
39
+ });
40
+
41
+ if (!res.ok) {
42
+ throw new Error(`Response was not ok when uploading media file.\nStatus, text: ${res.status}, ${res.statusText}`);
43
+ }
44
+ return true;
45
+ }
46
+ catch (e) {
47
+ console.error(`Error when uploading file to: ${preSignedUrl}\n${e}`);
48
+ return false;
49
+ }
50
+ }
51
+
52
+ static createUrlFromAssetKey(assetKey: string): string {
53
+ if (!assetKey) {
54
+ throw new Error(`Cannot create a url with an assetKey that is undefined`);
55
+ }
56
+ return `https://${process.env.CLOUDFRONT_ASSETS_URL}/${assetKey}`;
57
+ }
58
+
59
+ static async createPreSignedUrl(key: string | undefined, mimetype: string | undefined): Promise<string> {
60
+ if (!key || !mimetype) {
61
+ throw new Error(`Cannot create a pre-signed url without a key or a mimetype`);
62
+ }
63
+ const client = new S3Client({
64
+ credentials: {
65
+ accessKeyId: String(process.env.AWS_S3_ACCESS_KEY_ID),
66
+ secretAccessKey: String(process.env.AWS_S3_SECRET_ACCESS_KEY),
67
+ },
68
+ region: String(process.env.AWS_S3_REGION),
69
+ });
70
+ const command = new PutObjectCommand({
71
+ Bucket: String(process.env.AWS_S3_ASSETS_BUCKET_NAME),
72
+ Key: key,
73
+ ContentType: mimetype
74
+ });
75
+ return getSignedUrl(client, command, {
76
+ expiresIn: 3600,
77
+ });
78
+ }
79
+
80
+ static async deleteFile(key: string): Promise<DeleteObjectCommandOutput | undefined> {
81
+ try {
82
+ const command = new DeleteObjectCommand({
83
+ Bucket: String(process.env.AWS_S3_BUCKET_NAME),
84
+ Key: key,
85
+ });
86
+ const client = new S3Client({
87
+ credentials: {
88
+ accessKeyId: String(process.env.AWS_S3_ACCESS_KEY_ID),
89
+ secretAccessKey: String(process.env.AWS_S3_SECRET_ACCESS_KEY),
90
+ },
91
+ region: String(process.env.AWS_S3_REGION),
92
+ });
93
+ return client.send(command);
94
+ }
95
+ catch (e: any) {
96
+ console.error(e);
97
+ }
98
+ }
99
+ }
@@ -1,234 +1,234 @@
1
- import {DateType, DateValueType} from "react-tailwindcss-datepicker";
2
- import dayjs, {Dayjs} from "dayjs";
3
- import dayjsUtc from "dayjs/plugin/utc";
4
- import dayjsTimeZone from "dayjs/plugin/timezone";
5
- import {DateTimeArgType} from "../definitions";
6
-
7
- dayjs.extend(dayjsUtc);
8
- dayjs.extend(dayjsTimeZone);
9
-
10
-
11
- const PARSE_TIME_REG = /^(\d{1,2}):(\d{2}) ?([APM]{0,2})$/i;
12
-
13
- export const DATETIME_FORMAT_STANDARD = "MMM D, YYYY - h:mm A";
14
- export const DATETIME_FORMAT_ISO_LIKE = "YYYY-MM-DD HH:mm"
15
- export const DATE_FORMAT_STANDARD = "MM/DD/YYYY";
16
- export const DATE_FORMAT_ISO = "YYYY-MM-DD";
17
- export const TIME_FORMAT_AM_PM = "h:mm A";
18
-
19
- export interface ITime {
20
- hours: number;
21
- minutes: number;
22
- ampm: 'AM' | 'PM';
23
- }
24
-
25
- export function formatDateRange(startDateTimeArg: Date | null, endDateTimeArg: Date | null): string {
26
- const startDateTime = ensureDateTimeIsLocalDateTime(startDateTimeArg).tz(dayjs.tz.guess());
27
- const endDateTime = ensureDateTimeIsLocalDateTime(endDateTimeArg).tz(dayjs.tz.guess());
28
- if (startDateTime.isSame(endDateTime, 'day')) {
29
- return `${startDateTime.format(DATETIME_FORMAT_STANDARD)} to ${endDateTime.format(TIME_FORMAT_AM_PM)}`;
30
- }
31
-
32
- return `${startDateTime.format(DATETIME_FORMAT_STANDARD)} to ${endDateTime.format(DATETIME_FORMAT_STANDARD)}`;
33
- }
34
-
35
- export function ensureIsDateTime(possiblyADate: DateTimeArgType): Date | undefined {
36
- if (!possiblyADate) {
37
- return undefined;
38
- }
39
- return typeof possiblyADate === 'string' ? new Date(possiblyADate) : possiblyADate;
40
- }
41
-
42
- export function normalizeDate(validDate: Date | string | undefined | null): Date | undefined {
43
- if (!validDate) return undefined;
44
-
45
- const date = new Date(validDate);
46
-
47
- if (isNaN(date.getTime())) {
48
- console.error("Invalid date provided:", validDate);
49
- return undefined;
50
- }
51
-
52
- // Normalize to UTC and start of minute
53
- return dayjs(date).utc().startOf("minute").toDate();
54
- }
55
- export function normalizeDates(dates: (Date | string | undefined | null)[]): Date[] {
56
- return dates
57
- .map((date) => normalizeDate(date)) // Normalize each date
58
- .filter((date): date is Date => !!date); // Filter out invalid dates
59
- }
60
-
61
-
62
- export function formatDateTimeToISODateTimeString(date: DateTimeArgType): string | undefined {
63
- if (!date) {
64
- return undefined;
65
- }
66
- date = new Date(date);
67
- return date.toISOString();
68
- }
69
-
70
- export function dateWithinDateRange(date: DateTimeArgType, dateRange: DateValueType | undefined): boolean {
71
- const startDate = dayjs(dateRange?.startDate).startOf('day').toDate();
72
- const endDate = dayjs(dateRange?.endDate).endOf('day').toDate();
73
-
74
- return compareDateTime(date, startDate) >= 0 &&
75
- compareDateTime(date, endDate) < 0;
76
- }
77
-
78
- export function findLatestDateTime(date1Arg: DateTimeArgType, date2Arg: DateTimeArgType): Date | undefined {
79
- const date1 = dateTimeTypeToDate(date1Arg);
80
- const date2 = dateTimeTypeToDate(date2Arg);
81
- return compareDateTime(date1, date2) > 0 ? date1 : date2;
82
- }
83
-
84
- function dateTimeTypeToDate(date: DateTimeArgType): Date | undefined {
85
- if (typeof date === 'string') {
86
- return new Date(date);
87
- }
88
- else {
89
- return date ?? undefined;
90
- }
91
- }
92
-
93
- export function isDateTimeLaterThanNow(date: DateTimeArgType): boolean {
94
- return compareDateTime(date, new Date()) > 0;
95
- }
96
-
97
- export function areDateTimesEqual(date1: DateTimeArgType,
98
- date2: DateTimeArgType): boolean {
99
- return compareDateTime(date1, date2) === 0;
100
- }
101
-
102
- /**
103
- * Returns a 1 if date1 is later than date2; 0 if both dates are equal; -1 if date2 is later than date1
104
- * @param date1
105
- * @param date2
106
- */
107
- export function compareDateTime(date1: DateTimeArgType,
108
- date2: DateTimeArgType): number {
109
- if (!date1 && !date2) {
110
- return 0;
111
- }
112
- if (!date1) {
113
- return -1;
114
- }
115
- if (!date2) {
116
- return 1;
117
- }
118
- if (typeof date1 === 'string') {
119
- date1 = new Date(date1);
120
- }
121
- if (typeof date2 === 'string') {
122
- date2 = new Date(date2);
123
- }
124
-
125
- const date1Time = date1.getTime();
126
- const date2Time = date2.getTime();
127
-
128
- if (date1Time > date2Time) {
129
- return 1;
130
- }
131
- if (date1Time === date2Time) {
132
- return 0;
133
- }
134
- else {
135
- return -1;
136
- }
137
- }
138
-
139
- export function setDateButPreserveTime(
140
- dateArg: DateType,
141
- dateWithTheTimeYouWantToKeep: DateType | undefined
142
- ): Date {
143
- if (!dateArg || !dateWithTheTimeYouWantToKeep) {
144
- console.error("Invalid arguments:", { dateArg, dateWithTheTimeYouWantToKeep });
145
- throw new Error("Both dateArg and dateWithTheTimeYouWantToKeep are required.");
146
- }
147
-
148
- // Get local timezone
149
- const localTimeZone = dayjs.tz.guess();
150
-
151
- // Format date and time parts
152
- const datePart = dayjs(dateArg).tz(localTimeZone).format("YYYY-MM-DD"); // Local date
153
- const timePart = dayjs(dateWithTheTimeYouWantToKeep).tz(localTimeZone).format("HH:mm"); // Local time
154
-
155
- // Combine into an ISO string
156
- const combinedDateTimeString = `${datePart}T${timePart}`;
157
- console.log("Combining date and time:", {
158
- datePart,
159
- timePart,
160
- combinedDateTimeString,
161
- localTimeZone,
162
- });
163
-
164
- // Convert to UTC
165
- const combinedDateTime = dayjs.tz(combinedDateTimeString, localTimeZone).toDate();
166
- if (isNaN(combinedDateTime.getTime())) {
167
- console.error("Invalid combined datetime:", combinedDateTimeString);
168
- throw new Error("Invalid date or time format.");
169
- }
170
-
171
- console.log("Final combined DateTime (UTC):", combinedDateTime);
172
- return combinedDateTime;
173
- }
174
-
175
-
176
- export function setTimeOnDate(date: DateType | Date | undefined, parsedTime: ITime | null): Date {
177
- const isValidDate = dayjs(date).isValid();
178
- const dateTime = new Date(isValidDate && date ? date : Date.now());
179
- if (parsedTime) {
180
- const parsedTimeDate = new Date();
181
- parsedTimeDate.setHours(parsedTime.hours, parsedTime.minutes, 0); // Will change the date depending on time; corrected later
182
- const correctTimeOnDate = setDateButPreserveTime(dateTime, parsedTimeDate);
183
- return correctTimeOnDate;
184
- }
185
- return dateTime;
186
- }
187
-
188
- export function ensureDateTimeIsLocalDateTime(dateArg: DateType | Dayjs | undefined): Dayjs {
189
- if (dayjs(dateArg).isUTC()) {
190
- const dateLocalTimeZone = dayjs(dateArg);
191
- return dateLocalTimeZone;
192
- }
193
- else {
194
- return dayjs(dateArg ?? Date.now());
195
- }
196
- }
197
-
198
- export function formatDateTimeToTimeString(date: Date | string | undefined | null): string {
199
- date = new Date(date ?? Date.now());
200
- const result = dayjs(date).format("h:mm A");
201
- return result;
202
- }
203
-
204
- export function formatDateTimeToTimeString24hr(date: Date | string | undefined | null): string {
205
- date = new Date(date ?? Date.now());
206
- const result = dayjs(date).format("h:mm");
207
- return result;
208
- }
209
-
210
- export function parseTimeString(timeStr: string): ITime | null {
211
- const match = timeStr.match(PARSE_TIME_REG);
212
-
213
- if (match) {
214
- const hours = parseInt(match[1], 10);
215
- const minutes = parseInt(match[2], 10);
216
- const ampm = match[3].toUpperCase();
217
-
218
- if ((hours >= 0 && hours <= 12) && (minutes >= 0 && minutes <= 59) && (ampm === 'AM' || ampm === 'PM')) {
219
- return {
220
- hours: ampm === 'PM' && hours < 12 ? hours + 12 : hours,
221
- minutes,
222
- ampm };
223
- }
224
- }
225
- return null;
226
- }
227
-
228
- export function localDateToUTC(date: Date): Date {
229
- const newDate = new Date(date.getUTCFullYear(), date.getUTCMonth(),
230
- date.getUTCDate(), date.getUTCHours(),
231
- date.getUTCMinutes(), date.getUTCSeconds());
232
-
233
- return newDate;
234
- }
1
+ import {DateType, DateValueType} from "react-tailwindcss-datepicker";
2
+ import dayjs, {Dayjs} from "dayjs";
3
+ import dayjsUtc from "dayjs/plugin/utc";
4
+ import dayjsTimeZone from "dayjs/plugin/timezone";
5
+ import {DateTimeArgType} from "../definitions";
6
+
7
+ dayjs.extend(dayjsUtc);
8
+ dayjs.extend(dayjsTimeZone);
9
+
10
+
11
+ const PARSE_TIME_REG = /^(\d{1,2}):(\d{2}) ?([APM]{0,2})$/i;
12
+
13
+ export const DATETIME_FORMAT_STANDARD = "MMM D, YYYY - h:mm A";
14
+ export const DATETIME_FORMAT_ISO_LIKE = "YYYY-MM-DD HH:mm"
15
+ export const DATE_FORMAT_STANDARD = "MM/DD/YYYY";
16
+ export const DATE_FORMAT_ISO = "YYYY-MM-DD";
17
+ export const TIME_FORMAT_AM_PM = "h:mm A";
18
+
19
+ export interface ITime {
20
+ hours: number;
21
+ minutes: number;
22
+ ampm: 'AM' | 'PM';
23
+ }
24
+
25
+ export function formatDateRange(startDateTimeArg: Date | null, endDateTimeArg: Date | null): string {
26
+ const startDateTime = ensureDateTimeIsLocalDateTime(startDateTimeArg).tz(dayjs.tz.guess());
27
+ const endDateTime = ensureDateTimeIsLocalDateTime(endDateTimeArg).tz(dayjs.tz.guess());
28
+ if (startDateTime.isSame(endDateTime, 'day')) {
29
+ return `${startDateTime.format(DATETIME_FORMAT_STANDARD)} to ${endDateTime.format(TIME_FORMAT_AM_PM)}`;
30
+ }
31
+
32
+ return `${startDateTime.format(DATETIME_FORMAT_STANDARD)} to ${endDateTime.format(DATETIME_FORMAT_STANDARD)}`;
33
+ }
34
+
35
+ export function ensureIsDateTime(possiblyADate: DateTimeArgType): Date | undefined {
36
+ if (!possiblyADate) {
37
+ return undefined;
38
+ }
39
+ return typeof possiblyADate === 'string' ? new Date(possiblyADate) : possiblyADate;
40
+ }
41
+
42
+ export function normalizeDate(validDate: Date | string | undefined | null): Date | undefined {
43
+ if (!validDate) return undefined;
44
+
45
+ const date = new Date(validDate);
46
+
47
+ if (isNaN(date.getTime())) {
48
+ console.error("Invalid date provided:", validDate);
49
+ return undefined;
50
+ }
51
+
52
+ // Normalize to UTC and start of minute
53
+ return dayjs(date).utc().startOf("minute").toDate();
54
+ }
55
+ export function normalizeDates(dates: (Date | string | undefined | null)[]): Date[] {
56
+ return dates
57
+ .map((date) => normalizeDate(date)) // Normalize each date
58
+ .filter((date): date is Date => !!date); // Filter out invalid dates
59
+ }
60
+
61
+
62
+ export function formatDateTimeToISODateTimeString(date: DateTimeArgType): string | undefined {
63
+ if (!date) {
64
+ return undefined;
65
+ }
66
+ date = new Date(date);
67
+ return date.toISOString();
68
+ }
69
+
70
+ export function dateWithinDateRange(date: DateTimeArgType, dateRange: DateValueType | undefined): boolean {
71
+ const startDate = dayjs(dateRange?.startDate).startOf('day').toDate();
72
+ const endDate = dayjs(dateRange?.endDate).endOf('day').toDate();
73
+
74
+ return compareDateTime(date, startDate) >= 0 &&
75
+ compareDateTime(date, endDate) < 0;
76
+ }
77
+
78
+ export function findLatestDateTime(date1Arg: DateTimeArgType, date2Arg: DateTimeArgType): Date | undefined {
79
+ const date1 = dateTimeTypeToDate(date1Arg);
80
+ const date2 = dateTimeTypeToDate(date2Arg);
81
+ return compareDateTime(date1, date2) > 0 ? date1 : date2;
82
+ }
83
+
84
+ function dateTimeTypeToDate(date: DateTimeArgType): Date | undefined {
85
+ if (typeof date === 'string') {
86
+ return new Date(date);
87
+ }
88
+ else {
89
+ return date ?? undefined;
90
+ }
91
+ }
92
+
93
+ export function isDateTimeLaterThanNow(date: DateTimeArgType): boolean {
94
+ return compareDateTime(date, new Date()) > 0;
95
+ }
96
+
97
+ export function areDateTimesEqual(date1: DateTimeArgType,
98
+ date2: DateTimeArgType): boolean {
99
+ return compareDateTime(date1, date2) === 0;
100
+ }
101
+
102
+ /**
103
+ * Returns a 1 if date1 is later than date2; 0 if both dates are equal; -1 if date2 is later than date1
104
+ * @param date1
105
+ * @param date2
106
+ */
107
+ export function compareDateTime(date1: DateTimeArgType,
108
+ date2: DateTimeArgType): number {
109
+ if (!date1 && !date2) {
110
+ return 0;
111
+ }
112
+ if (!date1) {
113
+ return -1;
114
+ }
115
+ if (!date2) {
116
+ return 1;
117
+ }
118
+ if (typeof date1 === 'string') {
119
+ date1 = new Date(date1);
120
+ }
121
+ if (typeof date2 === 'string') {
122
+ date2 = new Date(date2);
123
+ }
124
+
125
+ const date1Time = date1.getTime();
126
+ const date2Time = date2.getTime();
127
+
128
+ if (date1Time > date2Time) {
129
+ return 1;
130
+ }
131
+ if (date1Time === date2Time) {
132
+ return 0;
133
+ }
134
+ else {
135
+ return -1;
136
+ }
137
+ }
138
+
139
+ export function setDateButPreserveTime(
140
+ dateArg: DateType,
141
+ dateWithTheTimeYouWantToKeep: DateType | undefined
142
+ ): Date {
143
+ if (!dateArg || !dateWithTheTimeYouWantToKeep) {
144
+ console.error("Invalid arguments:", { dateArg, dateWithTheTimeYouWantToKeep });
145
+ throw new Error("Both dateArg and dateWithTheTimeYouWantToKeep are required.");
146
+ }
147
+
148
+ // Get local timezone
149
+ const localTimeZone = dayjs.tz.guess();
150
+
151
+ // Format date and time parts
152
+ const datePart = dayjs(dateArg).tz(localTimeZone).format("YYYY-MM-DD"); // Local date
153
+ const timePart = dayjs(dateWithTheTimeYouWantToKeep).tz(localTimeZone).format("HH:mm"); // Local time
154
+
155
+ // Combine into an ISO string
156
+ const combinedDateTimeString = `${datePart}T${timePart}`;
157
+ console.log("Combining date and time:", {
158
+ datePart,
159
+ timePart,
160
+ combinedDateTimeString,
161
+ localTimeZone,
162
+ });
163
+
164
+ // Convert to UTC
165
+ const combinedDateTime = dayjs.tz(combinedDateTimeString, localTimeZone).toDate();
166
+ if (isNaN(combinedDateTime.getTime())) {
167
+ console.error("Invalid combined datetime:", combinedDateTimeString);
168
+ throw new Error("Invalid date or time format.");
169
+ }
170
+
171
+ console.log("Final combined DateTime (UTC):", combinedDateTime);
172
+ return combinedDateTime;
173
+ }
174
+
175
+
176
+ export function setTimeOnDate(date: DateType | Date | undefined, parsedTime: ITime | null): Date {
177
+ const isValidDate = dayjs(date).isValid();
178
+ const dateTime = new Date(isValidDate && date ? date : Date.now());
179
+ if (parsedTime) {
180
+ const parsedTimeDate = new Date();
181
+ parsedTimeDate.setHours(parsedTime.hours, parsedTime.minutes, 0); // Will change the date depending on time; corrected later
182
+ const correctTimeOnDate = setDateButPreserveTime(dateTime, parsedTimeDate);
183
+ return correctTimeOnDate;
184
+ }
185
+ return dateTime;
186
+ }
187
+
188
+ export function ensureDateTimeIsLocalDateTime(dateArg: DateType | Dayjs | undefined): Dayjs {
189
+ if (dayjs(dateArg).isUTC()) {
190
+ const dateLocalTimeZone = dayjs(dateArg);
191
+ return dateLocalTimeZone;
192
+ }
193
+ else {
194
+ return dayjs(dateArg ?? Date.now());
195
+ }
196
+ }
197
+
198
+ export function formatDateTimeToTimeString(date: Date | string | undefined | null): string {
199
+ date = new Date(date ?? Date.now());
200
+ const result = dayjs(date).format("h:mm A");
201
+ return result;
202
+ }
203
+
204
+ export function formatDateTimeToTimeString24hr(date: Date | string | undefined | null): string {
205
+ date = new Date(date ?? Date.now());
206
+ const result = dayjs(date).format("h:mm");
207
+ return result;
208
+ }
209
+
210
+ export function parseTimeString(timeStr: string): ITime | null {
211
+ const match = timeStr.match(PARSE_TIME_REG);
212
+
213
+ if (match) {
214
+ const hours = parseInt(match[1], 10);
215
+ const minutes = parseInt(match[2], 10);
216
+ const ampm = match[3].toUpperCase();
217
+
218
+ if ((hours >= 0 && hours <= 12) && (minutes >= 0 && minutes <= 59) && (ampm === 'AM' || ampm === 'PM')) {
219
+ return {
220
+ hours: ampm === 'PM' && hours < 12 ? hours + 12 : hours,
221
+ minutes,
222
+ ampm };
223
+ }
224
+ }
225
+ return null;
226
+ }
227
+
228
+ export function localDateToUTC(date: Date): Date {
229
+ const newDate = new Date(date.getUTCFullYear(), date.getUTCMonth(),
230
+ date.getUTCDate(), date.getUTCHours(),
231
+ date.getUTCMinutes(), date.getUTCSeconds());
232
+
233
+ return newDate;
234
+ }