@oneuptime/common 10.0.46 → 10.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts +5 -1
  2. package/Server/Services/DashboardService.ts +26 -0
  3. package/Tests/Models/AnalyticsModels/Log.test.ts +15 -0
  4. package/Tests/Types/Date.test.ts +6 -0
  5. package/Tests/UI/Components/XAxis.test.ts +30 -0
  6. package/Types/Date.ts +100 -2
  7. package/UI/Components/Charts/Utils/XAxis.ts +93 -104
  8. package/UI/Components/LogsViewer/LogsViewer.tsx +5 -2
  9. package/UI/Components/LogsViewer/components/HistogramTooltip.tsx +2 -1
  10. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +1 -1
  11. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +3 -2
  12. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +4 -3
  13. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.js +3 -1
  14. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.js.map +1 -1
  15. package/build/dist/Server/Services/DashboardService.js +12 -0
  16. package/build/dist/Server/Services/DashboardService.js.map +1 -1
  17. package/build/dist/Tests/Models/AnalyticsModels/Log.test.js +12 -0
  18. package/build/dist/Tests/Models/AnalyticsModels/Log.test.js.map +1 -0
  19. package/build/dist/Tests/Types/Date.test.js +3 -0
  20. package/build/dist/Tests/Types/Date.test.js.map +1 -1
  21. package/build/dist/Tests/UI/Components/XAxis.test.js +22 -0
  22. package/build/dist/Tests/UI/Components/XAxis.test.js.map +1 -0
  23. package/build/dist/Types/Date.js +68 -2
  24. package/build/dist/Types/Date.js.map +1 -1
  25. package/build/dist/UI/Components/Charts/Utils/XAxis.js +80 -104
  26. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  27. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +5 -2
  28. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  29. package/build/dist/UI/Components/LogsViewer/components/HistogramTooltip.js +2 -1
  30. package/build/dist/UI/Components/LogsViewer/components/HistogramTooltip.js.map +1 -1
  31. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +1 -1
  32. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  33. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +3 -2
  34. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  35. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +4 -3
  36. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  37. package/package.json +1 -1
@@ -69,7 +69,11 @@ export default class CommonModel {
69
69
  value = new ObjectID(value as string | JSONObject);
70
70
  }
71
71
 
72
- if (column.type === TableColumnType.Date && typeof value === "string") {
72
+ if (
73
+ (column.type === TableColumnType.Date ||
74
+ column.type === TableColumnType.DateTime64) &&
75
+ typeof value === "string"
76
+ ) {
73
77
  value = OneUptimeDate.fromString(value);
74
78
  }
75
79
 
@@ -13,6 +13,11 @@ import Model from "../../Models/DatabaseModels/Dashboard";
13
13
  import { IsBillingEnabled } from "../EnvironmentConfig";
14
14
  import { PlanType } from "../../Types/Billing/SubscriptionPlan";
15
15
  import DashboardViewConfigUtil from "../../Utils/Dashboard/DashboardViewConfig";
16
+ import {
17
+ DashboardTemplateType,
18
+ getTemplateConfig,
19
+ } from "../../Types/Dashboard/DashboardTemplates";
20
+ import DashboardViewConfig from "../../Types/Dashboard/DashboardViewConfig";
16
21
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
17
22
  import ObjectID from "../../Types/ObjectID";
18
23
  import { JSONObject } from "../../Types/JSON";
@@ -55,6 +60,27 @@ export class Service extends DatabaseService<Model> {
55
60
  }
56
61
  }
57
62
 
63
+ // Check if a template type was provided via miscDataProps
64
+ const templateType: string | undefined = createBy.miscDataProps?.[
65
+ "dashboardTemplateType"
66
+ ] as string | undefined;
67
+
68
+ if (
69
+ templateType &&
70
+ templateType !== DashboardTemplateType.Blank &&
71
+ Object.values(DashboardTemplateType).includes(
72
+ templateType as DashboardTemplateType,
73
+ )
74
+ ) {
75
+ const templateConfig: DashboardViewConfig | null = getTemplateConfig(
76
+ templateType as DashboardTemplateType,
77
+ );
78
+
79
+ if (templateConfig) {
80
+ createBy.data.dashboardViewConfig = templateConfig;
81
+ }
82
+ }
83
+
58
84
  // use default empty config only if no template config was provided.
59
85
  if (
60
86
  !createBy.data.dashboardViewConfig ||
@@ -0,0 +1,15 @@
1
+ import Log from "../../../Models/AnalyticsModels/Log";
2
+
3
+ describe("Analytics Log model", () => {
4
+ test("should deserialize ClickHouse DateTime64 values as Date objects", () => {
5
+ const log: Log = Log.fromJSON(
6
+ {
7
+ time: "2026-04-01 14:45:31.414000000",
8
+ },
9
+ Log,
10
+ ) as Log;
11
+
12
+ expect(log.time).toBeInstanceOf(Date);
13
+ expect(log.time?.toISOString()).toBe("2026-04-01T14:45:31.414Z");
14
+ });
15
+ });
@@ -86,4 +86,10 @@ describe("class OneUptimeDate", () => {
86
86
  OneUptimeDate.getSomeSecondsAfter(new PositiveNumber(4)).getSeconds(),
87
87
  ).toEqual(moment().add(4, "seconds").toDate().getSeconds());
88
88
  });
89
+
90
+ test("OneUptimeDate.fromString should parse ClickHouse timestamps as UTC", () => {
91
+ expect(
92
+ OneUptimeDate.fromString("2026-04-01 14:45:31.414000000").toISOString(),
93
+ ).toBe("2026-04-01T14:45:31.414Z");
94
+ });
89
95
  });
@@ -0,0 +1,30 @@
1
+ // eslint-disable-next-line no-undef
2
+ process.env.TZ = "Europe/London";
3
+
4
+ import XAxisUtil from "../../../UI/Components/Charts/Utils/XAxis";
5
+
6
+ describe("XAxisUtil", () => {
7
+ test("formats past-day chart labels in local BST time instead of UTC", () => {
8
+ const formatter: (value: Date) => string = XAxisUtil.getFormatter({
9
+ xAxisMin: new Date("2026-04-06T14:00:00.000Z"),
10
+ xAxisMax: new Date("2026-04-07T14:00:00.000Z"),
11
+ });
12
+
13
+ expect(formatter(new Date("2026-04-07T07:30:00.000Z"))).toBe(
14
+ "07 Apr, 08:00",
15
+ );
16
+ });
17
+
18
+ test("does not mutate the original date while rounding local labels", () => {
19
+ const formatter: (value: Date) => string = XAxisUtil.getFormatter({
20
+ xAxisMin: new Date("2026-04-06T14:00:00.000Z"),
21
+ xAxisMax: new Date("2026-04-07T14:00:00.000Z"),
22
+ });
23
+
24
+ const originalDate: Date = new Date("2026-04-07T07:30:45.000Z");
25
+
26
+ formatter(originalDate);
27
+
28
+ expect(originalDate.toISOString()).toBe("2026-04-07T07:30:45.000Z");
29
+ });
30
+ });
package/Types/Date.ts CHANGED
@@ -12,6 +12,41 @@ export const Moment: typeof moment = moment;
12
12
  export default class OneUptimeDate {
13
13
  // get date time from unix timestamp
14
14
 
15
+ private static padDatePart(value: number): string {
16
+ return value.toString().padStart(2, "0");
17
+ }
18
+
19
+ private static isUtcDateTimeString(value: string): boolean {
20
+ const utcDateTimePattern: RegExp =
21
+ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d{1,9})?$/;
22
+
23
+ return utcDateTimePattern.test(value.trim());
24
+ }
25
+
26
+ private static normalizeUtcDateTimeString(value: string): string {
27
+ const trimmedValue: string = value.trim();
28
+ const [datePart, timePart] = trimmedValue.split(" ");
29
+
30
+ if (!datePart || !timePart) {
31
+ return trimmedValue;
32
+ }
33
+
34
+ const [baseTime, fractionalPart] = timePart.split(".");
35
+
36
+ if (!fractionalPart) {
37
+ return `${datePart}T${baseTime}Z`;
38
+ }
39
+
40
+ const milliseconds: string = fractionalPart.slice(0, 3).padEnd(3, "0");
41
+ return `${datePart}T${baseTime}.${milliseconds}Z`;
42
+ }
43
+
44
+ private static getLocalShortMonthName(date: Date): string {
45
+ return date.toLocaleString("default", {
46
+ month: "short",
47
+ });
48
+ }
49
+
15
50
  public static getSchema(): ZodSchema {
16
51
  return Zod.object({
17
52
  _type: Zod.literal(ObjectType.DateTime),
@@ -106,8 +141,63 @@ export default class OneUptimeDate {
106
141
  }
107
142
 
108
143
  public static getLocalHourAndMinuteFromDate(date: Date | string): string {
144
+ return this.getLocalTimeString(date);
145
+ }
146
+
147
+ public static getLocalShortMonthNameFromDate(date: Date | string): string {
109
148
  date = this.fromString(date);
110
- return moment(date).format("HH:mm");
149
+ return this.getLocalShortMonthName(date);
150
+ }
151
+
152
+ public static getLocalTimeString(
153
+ date: Date | string,
154
+ options?: {
155
+ includeMinutes?: boolean;
156
+ includeSeconds?: boolean;
157
+ },
158
+ ): string {
159
+ date = this.fromString(date);
160
+
161
+ const includeMinutes: boolean = options?.includeMinutes ?? true;
162
+ const includeSeconds: boolean = options?.includeSeconds ?? false;
163
+ const hours: string = this.padDatePart(date.getHours());
164
+
165
+ if (!includeMinutes) {
166
+ return hours;
167
+ }
168
+
169
+ const minutes: string = this.padDatePart(date.getMinutes());
170
+
171
+ if (!includeSeconds) {
172
+ return `${hours}:${minutes}`;
173
+ }
174
+
175
+ const seconds: string = this.padDatePart(date.getSeconds());
176
+ return `${hours}:${minutes}:${seconds}`;
177
+ }
178
+
179
+ public static getDateAsLocalDayMonthString(date: Date | string): string {
180
+ date = this.fromString(date);
181
+
182
+ const day: string = this.padDatePart(date.getDate());
183
+ const month: string = this.getLocalShortMonthName(date);
184
+
185
+ return `${day} ${month}`;
186
+ }
187
+
188
+ public static getDateAsLocalDayMonthHourString(date: Date | string): string {
189
+ date = this.fromString(date);
190
+
191
+ return `${this.getDateAsLocalDayMonthString(date)}, ${this.getLocalTimeString(date, { includeMinutes: false })}:00`;
192
+ }
193
+
194
+ public static getDateAsLocalMonthYearString(date: Date | string): string {
195
+ date = this.fromString(date);
196
+
197
+ const month: string = this.getLocalShortMonthName(date);
198
+ const year: string = date.getFullYear().toString();
199
+
200
+ return `${month} ${year}`;
111
201
  }
112
202
 
113
203
  public static getMillisecondsBetweenTwoUnixNanoDates(
@@ -1442,7 +1532,15 @@ export default class OneUptimeDate {
1442
1532
  }
1443
1533
 
1444
1534
  if (typeof date === "string") {
1445
- return moment(date).toDate();
1535
+ const trimmedDate: string = date.trim();
1536
+
1537
+ if (this.isUtcDateTimeString(trimmedDate)) {
1538
+ return moment
1539
+ .utc(this.normalizeUtcDateTimeString(trimmedDate))
1540
+ .toDate();
1541
+ }
1542
+
1543
+ return moment(trimmedDate).toDate();
1446
1544
  }
1447
1545
 
1448
1546
  if (
@@ -4,6 +4,10 @@ import XAxisMaxMin from "../Types/XAxis/XAxisMaxMin";
4
4
  import XAxisPrecision from "../Types/XAxis/XAxisPrecision";
5
5
 
6
6
  export default class XAxisUtil {
7
+ private static cloneDate(value: Date): Date {
8
+ return new Date(value.getTime());
9
+ }
10
+
7
11
  public static getPrecision(data: {
8
12
  xAxisMin: XAxisMaxMin;
9
13
  xAxisMax: XAxisMaxMin;
@@ -203,211 +207,196 @@ export default class XAxisUtil {
203
207
  switch (precision) {
204
208
  case XAxisPrecision.EVERY_SECOND:
205
209
  return (value: Date) => {
206
- // round down to nearest second
207
- return value.toISOString().substring(11, 19);
210
+ return OneUptimeDate.getLocalTimeString(value, {
211
+ includeSeconds: true,
212
+ });
208
213
  };
209
214
  case XAxisPrecision.EVERY_FIVE_SECONDS:
210
215
  // round down to nearest 5 seconds
211
216
  return (value: Date) => {
212
- const seconds: number = value.getSeconds();
217
+ const roundedValue: Date = this.cloneDate(value);
218
+ const seconds: number = roundedValue.getSeconds();
213
219
  const roundedSeconds: number = Math.floor(seconds / 5) * 5;
214
- value.setSeconds(roundedSeconds);
215
- return value.toISOString().substring(11, 19);
220
+ roundedValue.setSeconds(roundedSeconds, 0);
221
+
222
+ return OneUptimeDate.getLocalTimeString(roundedValue, {
223
+ includeSeconds: true,
224
+ });
216
225
  };
217
226
  case XAxisPrecision.EVERY_TEN_SECONDS:
218
227
  // round down to nearest 10 seconds
219
228
  return (value: Date) => {
220
- const seconds: number = value.getSeconds();
229
+ const roundedValue: Date = this.cloneDate(value);
230
+ const seconds: number = roundedValue.getSeconds();
221
231
  const roundedSeconds: number = Math.floor(seconds / 10) * 10;
222
- value.setSeconds(roundedSeconds);
223
- return value.toISOString().substring(11, 19);
232
+ roundedValue.setSeconds(roundedSeconds, 0);
233
+
234
+ return OneUptimeDate.getLocalTimeString(roundedValue, {
235
+ includeSeconds: true,
236
+ });
224
237
  };
225
238
  case XAxisPrecision.EVERY_THIRTY_SECONDS:
226
239
  // round down to nearest 30 seconds
227
240
  return (value: Date) => {
228
- const seconds: number = value.getSeconds();
241
+ const roundedValue: Date = this.cloneDate(value);
242
+ const seconds: number = roundedValue.getSeconds();
229
243
  const roundedSeconds: number = Math.floor(seconds / 30) * 30;
230
- value.setSeconds(roundedSeconds);
231
- return value.toISOString().substring(11, 19);
244
+ roundedValue.setSeconds(roundedSeconds, 0);
245
+
246
+ return OneUptimeDate.getLocalTimeString(roundedValue, {
247
+ includeSeconds: true,
248
+ });
232
249
  };
233
250
  case XAxisPrecision.EVERY_MINUTE:
234
251
  // round down to nearest minute
235
252
  return (value: Date) => {
236
- return value.toISOString().substring(11, 16);
253
+ return OneUptimeDate.getLocalTimeString(value);
237
254
  };
238
255
  case XAxisPrecision.EVERY_FIVE_MINUTES:
239
256
  // round down to nearest 5 minutes
240
257
  return (value: Date) => {
241
- const minutes: number = value.getMinutes();
258
+ const roundedValue: Date = this.cloneDate(value);
259
+ const minutes: number = roundedValue.getMinutes();
242
260
  const roundedMinutes: number = Math.floor(minutes / 5) * 5;
243
- value.setMinutes(roundedMinutes);
244
- return value.toISOString().substring(11, 16);
261
+ roundedValue.setMinutes(roundedMinutes, 0, 0);
262
+
263
+ return OneUptimeDate.getLocalTimeString(roundedValue);
245
264
  };
246
265
  case XAxisPrecision.EVERY_TEN_MINUTES:
247
266
  // round down to nearest 10 minutes
248
267
  return (value: Date) => {
249
- const minutes: number = value.getMinutes();
268
+ const roundedValue: Date = this.cloneDate(value);
269
+ const minutes: number = roundedValue.getMinutes();
250
270
  const roundedMinutes: number = Math.floor(minutes / 10) * 10;
251
- value.setMinutes(roundedMinutes);
252
- return value.toISOString().substring(11, 16);
271
+ roundedValue.setMinutes(roundedMinutes, 0, 0);
272
+
273
+ return OneUptimeDate.getLocalTimeString(roundedValue);
253
274
  };
254
275
  case XAxisPrecision.EVERY_THIRTY_MINUTES:
255
276
  // round down to nearest 30 minutes
256
277
  return (value: Date) => {
257
- const minutes: number = value.getMinutes();
278
+ const roundedValue: Date = this.cloneDate(value);
279
+ const minutes: number = roundedValue.getMinutes();
258
280
  const roundedMinutes: number = Math.floor(minutes / 30) * 30;
259
- value.setMinutes(roundedMinutes);
260
- return value.toISOString().substring(11, 16);
281
+ roundedValue.setMinutes(roundedMinutes, 0, 0);
282
+
283
+ return OneUptimeDate.getLocalTimeString(roundedValue);
261
284
  };
262
285
  case XAxisPrecision.EVERY_HOUR:
263
286
  return (value: Date) => {
264
- return value.toISOString().substring(11, 13);
287
+ return OneUptimeDate.getLocalTimeString(value, {
288
+ includeMinutes: false,
289
+ });
265
290
  }; // HH:00
266
291
  case XAxisPrecision.EVERY_TWO_HOURS:
267
292
  return (value: Date) => {
268
- const hours: number = value.getHours();
293
+ const roundedValue: Date = this.cloneDate(value);
294
+ const hours: number = roundedValue.getHours();
269
295
  const roundedHours: number = Math.floor(hours / 2) * 2;
270
- value.setHours(roundedHours);
296
+ roundedValue.setHours(roundedHours, 0, 0, 0);
271
297
 
272
- const dateString: string = value.toISOString();
273
- const day: string = dateString.substring(8, 10);
274
- const month: string = value.toLocaleString("default", {
275
- month: "short",
276
- });
277
- return `${day} ${month}, ${value.toISOString().substring(11, 13)}:00`;
298
+ return OneUptimeDate.getDateAsLocalDayMonthHourString(roundedValue);
278
299
  };
279
300
  case XAxisPrecision.EVERY_THREE_HOURS:
280
301
  // round down to nearest 3 hours
281
302
  return (value: Date) => {
282
- const hours: number = value.getHours();
303
+ const roundedValue: Date = this.cloneDate(value);
304
+ const hours: number = roundedValue.getHours();
283
305
  const roundedHours: number = Math.floor(hours / 3) * 3;
284
- value.setHours(roundedHours);
306
+ roundedValue.setHours(roundedHours, 0, 0, 0);
285
307
 
286
- const dateString: string = value.toISOString();
287
- const day: string = dateString.substring(8, 10);
288
- const month: string = value.toLocaleString("default", {
289
- month: "short",
290
- });
291
- return `${day} ${month}, ${value.toISOString().substring(11, 13)}:00`;
308
+ return OneUptimeDate.getDateAsLocalDayMonthHourString(roundedValue);
292
309
  };
293
310
  case XAxisPrecision.EVERY_SIX_HOURS:
294
311
  // round down to nearest 6 hours // HH:00 DD MMM
295
312
  return (value: Date) => {
296
- const hours: number = value.getHours();
313
+ const roundedValue: Date = this.cloneDate(value);
314
+ const hours: number = roundedValue.getHours();
297
315
  const roundedHours: number = Math.floor(hours / 6) * 6;
298
- value.setHours(roundedHours);
316
+ roundedValue.setHours(roundedHours, 0, 0, 0);
299
317
 
300
- const dateString: string = value.toISOString();
301
- const day: string = dateString.substring(8, 10);
302
- const month: string = value.toLocaleString("default", {
303
- month: "short",
304
- });
305
- return `${day} ${month}, ${value.toISOString().substring(11, 13)}:00`;
318
+ return OneUptimeDate.getDateAsLocalDayMonthHourString(roundedValue);
306
319
  };
307
320
  case XAxisPrecision.EVERY_TWELVE_HOURS:
308
321
  // round down to nearest 12 hours // DD MMM, HH:00
309
322
  return (value: Date) => {
310
- const hours: number = value.getHours();
323
+ const roundedValue: Date = this.cloneDate(value);
324
+ const hours: number = roundedValue.getHours();
311
325
  const roundedHours: number = Math.floor(hours / 12) * 12;
312
- value.setHours(roundedHours);
326
+ roundedValue.setHours(roundedHours, 0, 0, 0);
313
327
 
314
- const dateString: string = value.toISOString();
315
- const day: string = dateString.substring(8, 10);
316
- const month: string = value.toLocaleString("default", {
317
- month: "short",
318
- });
319
- const hour: string = dateString.substring(11, 13);
320
- return `${day} ${month}, ${hour}:00`;
328
+ return OneUptimeDate.getDateAsLocalDayMonthHourString(roundedValue);
321
329
  };
322
330
  case XAxisPrecision.EVERY_DAY:
323
331
  // round down to nearest day
324
332
  return (value: Date) => {
325
- const dateString: string = value.toISOString();
326
- const day: string = dateString.substring(8, 10);
327
- const month: string = value.toLocaleString("default", {
328
- month: "short",
329
- });
330
- return `${day} ${month}`;
333
+ return OneUptimeDate.getDateAsLocalDayMonthString(value);
331
334
  };
332
335
  case XAxisPrecision.EVERY_TWO_DAYS:
333
336
  // round down to nearest 2 days
334
337
  return (value: Date) => {
335
- const days: number = value.getDate();
338
+ const roundedValue: Date = this.cloneDate(value);
339
+ const days: number = roundedValue.getDate();
336
340
  const roundedDays: number = Math.floor(days / 2) * 2;
337
- value.setDate(roundedDays);
338
- const dateString: string = value.toISOString();
339
- const day: string = dateString.substring(8, 10);
340
- const month: string = value.toLocaleString("default", {
341
- month: "short",
342
- });
343
- return `${day} ${month}`;
341
+ roundedValue.setDate(roundedDays);
342
+
343
+ return OneUptimeDate.getDateAsLocalDayMonthString(roundedValue);
344
344
  };
345
345
  case XAxisPrecision.EVERY_WEEK:
346
346
  // round down to nearest week
347
347
  return (value: Date) => {
348
348
  const day: string = value.getDate().toString();
349
- const month: string = value.toLocaleString("default", {
350
- month: "short",
351
- });
349
+ const month: string =
350
+ OneUptimeDate.getLocalShortMonthNameFromDate(value);
352
351
  return `${day} ${month}`;
353
352
  };
354
353
  case XAxisPrecision.EVERY_TWO_WEEKS:
355
354
  // round down to nearest 2 weeks. // DD MMM
356
355
  return (value: Date) => {
357
- const days: number = value.getDate();
356
+ const roundedValue: Date = this.cloneDate(value);
357
+ const days: number = roundedValue.getDate();
358
358
  const roundedDays: number = Math.floor(days / 2) * 2;
359
- value.setDate(roundedDays);
360
- const day: string = value.getDate().toString();
361
- const month: string = value.toLocaleString("default", {
362
- month: "short",
363
- });
359
+ roundedValue.setDate(roundedDays);
360
+ const day: string = roundedValue.getDate().toString();
361
+ const month: string =
362
+ OneUptimeDate.getLocalShortMonthNameFromDate(roundedValue);
364
363
  return `${day} ${month}`;
365
364
  };
366
365
  case XAxisPrecision.EVERY_MONTH:
367
366
  // round down to nearest month // MM YYYY
368
367
  return (value: Date) => {
369
- const month: string = value.toLocaleString("default", {
370
- month: "short",
371
- });
372
- const year: string = value.getFullYear().toString();
373
- return `${month} ${year}`;
368
+ return OneUptimeDate.getDateAsLocalMonthYearString(value);
374
369
  };
375
370
 
376
371
  case XAxisPrecision.EVERY_TWO_MONTHS:
377
372
  // round down to nearest 2 months // MM YYYY
378
373
  return (value: Date) => {
379
- const months: number = value.getMonth();
374
+ const roundedValue: Date = this.cloneDate(value);
375
+ const months: number = roundedValue.getMonth();
380
376
  const roundedMonths: number = Math.floor(months / 2) * 2;
381
- value.setMonth(roundedMonths);
382
- const month: string = value.toLocaleString("default", {
383
- month: "short",
384
- });
385
- const year: string = value.getFullYear().toString();
386
- return `${month} ${year}`;
377
+ roundedValue.setMonth(roundedMonths);
378
+
379
+ return OneUptimeDate.getDateAsLocalMonthYearString(roundedValue);
387
380
  };
388
381
  case XAxisPrecision.EVERY_THREE_MONTHS:
389
382
  // round down to nearest 3 months // MM YYYY
390
383
  return (value: Date) => {
391
- const months: number = value.getMonth();
384
+ const roundedValue: Date = this.cloneDate(value);
385
+ const months: number = roundedValue.getMonth();
392
386
  const roundedMonths: number = Math.floor(months / 3) * 3;
393
- value.setMonth(roundedMonths);
394
- const month: string = value.toLocaleString("default", {
395
- month: "short",
396
- });
397
- const year: string = value.getFullYear().toString();
398
- return `${month} ${year}`;
387
+ roundedValue.setMonth(roundedMonths);
388
+
389
+ return OneUptimeDate.getDateAsLocalMonthYearString(roundedValue);
399
390
  };
400
391
  case XAxisPrecision.EVERY_SIX_MONTHS:
401
392
  // round down to nearest 6 months // MM YYYY
402
393
  return (value: Date) => {
403
- const months: number = value.getMonth();
394
+ const roundedValue: Date = this.cloneDate(value);
395
+ const months: number = roundedValue.getMonth();
404
396
  const roundedMonths: number = Math.floor(months / 6) * 6;
405
- value.setMonth(roundedMonths);
406
- const month: string = value.toLocaleString("default", {
407
- month: "short",
408
- });
409
- const year: string = value.getFullYear().toString();
410
- return `${month} ${year}`;
397
+ roundedValue.setMonth(roundedMonths);
398
+
399
+ return OneUptimeDate.getDateAsLocalMonthYearString(roundedValue);
411
400
  };
412
401
  case XAxisPrecision.EVERY_YEAR:
413
402
  // round down to nearest year // YYYY
@@ -58,6 +58,7 @@ import RangeStartAndEndDateTime from "../../../Types/Time/RangeStartAndEndDateTi
58
58
  import TimeRange from "../../../Types/Time/TimeRange";
59
59
  import { exportLogs, LogExportFormat } from "../../Utils/LogExport";
60
60
  import ObjectID from "../../../Types/ObjectID";
61
+ import OneUptimeDate from "../../../Types/Date";
61
62
 
62
63
  export interface ComponentProps {
63
64
  logs: Array<Log>;
@@ -279,9 +280,11 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
279
280
  cloned.sort((a: Log, b: Log) => {
280
281
  if (sortField === "time") {
281
282
  const aTime: number =
282
- Number(a.timeUnixNano) || (a.time ? new Date(a.time).getTime() : 0);
283
+ Number(a.timeUnixNano) ||
284
+ (a.time ? OneUptimeDate.fromString(a.time).getTime() : 0);
283
285
  const bTime: number =
284
- Number(b.timeUnixNano) || (b.time ? new Date(b.time).getTime() : 0);
286
+ Number(b.timeUnixNano) ||
287
+ (b.time ? OneUptimeDate.fromString(b.time).getTime() : 0);
285
288
 
286
289
  if (aTime === bTime) {
287
290
  return 0;
@@ -1,4 +1,5 @@
1
1
  import React, { FunctionComponent, ReactElement } from "react";
2
+ import OneUptimeDate from "../../../../Types/Date";
2
3
  import { getSeverityColor } from "./severityColors";
3
4
 
4
5
  export interface TooltipEntry {
@@ -21,7 +22,7 @@ function formatTooltipTime(label: string | undefined): string {
21
22
  return "";
22
23
  }
23
24
 
24
- const date: Date = new Date(label);
25
+ const date: Date = OneUptimeDate.fromString(label);
25
26
 
26
27
  if (isNaN(date.getTime())) {
27
28
  return label;
@@ -285,7 +285,7 @@ const LogDetailsPanel: FunctionComponent<LogDetailsPanelProps> = (
285
285
  <span className="flex-none whitespace-nowrap font-mono text-[11px] text-gray-400">
286
286
  {ctxLog.time
287
287
  ? OneUptimeDate.getDateAsUserFriendlyFormattedString(
288
- new Date(ctxLog.time),
288
+ OneUptimeDate.fromString(ctxLog.time),
289
289
  )
290
290
  : "-"}
291
291
  </span>
@@ -29,6 +29,7 @@ import { JSONObject } from "../../../../Types/JSON";
29
29
  import { APP_API_URL } from "../../../Config";
30
30
  import ModelAPI from "../../../Utils/ModelAPI/ModelAPI";
31
31
  import ComponentLoader from "../../ComponentLoader/ComponentLoader";
32
+ import OneUptimeDate from "../../../../Types/Date";
32
33
 
33
34
  type AnalyticsChartType = "timeseries" | "toplist" | "table";
34
35
  type AnalyticsAggregation = "count" | "unique";
@@ -124,7 +125,7 @@ function pivotTimeseriesData(rows: Array<AnalyticsTimeseriesRow>): {
124
125
  }
125
126
 
126
127
  function formatTickTime(time: string): string {
127
- const date: Date = new Date(time);
128
+ const date: Date = OneUptimeDate.fromString(time);
128
129
 
129
130
  if (isNaN(date.getTime())) {
130
131
  return time;
@@ -230,7 +231,7 @@ const AnalyticsTooltip: FunctionComponent<AnalyticsTooltipProps> = (
230
231
  return "";
231
232
  }
232
233
 
233
- const date: Date = new Date(label);
234
+ const date: Date = OneUptimeDate.fromString(label);
234
235
 
235
236
  if (isNaN(date.getTime())) {
236
237
  return label;
@@ -23,6 +23,7 @@ import {
23
23
  } from "./severityColors";
24
24
  import HistogramTooltip from "./HistogramTooltip";
25
25
  import ComponentLoader from "../../ComponentLoader/ComponentLoader";
26
+ import OneUptimeDate from "../../../../Types/Date";
26
27
 
27
28
  export interface LogsHistogramProps {
28
29
  buckets: Array<HistogramBucket>;
@@ -54,7 +55,7 @@ function pivotBuckets(buckets: Array<HistogramBucket>): Array<PivotedRow> {
54
55
  }
55
56
 
56
57
  function formatTickTime(time: string): string {
57
- const date: Date = new Date(time);
58
+ const date: Date = OneUptimeDate.fromString(time);
58
59
 
59
60
  if (isNaN(date.getTime())) {
60
61
  return time;
@@ -138,8 +139,8 @@ const LogsHistogram: FunctionComponent<LogsHistogramProps> = (
138
139
 
139
140
  isSelecting.current = false;
140
141
 
141
- const start: Date = new Date(selectionStart);
142
- const end: Date = new Date(selectionEnd);
142
+ const start: Date = OneUptimeDate.fromString(selectionStart);
143
+ const end: Date = OneUptimeDate.fromString(selectionEnd);
143
144
 
144
145
  if (isNaN(start.getTime()) || isNaN(end.getTime())) {
145
146
  setSelectionStart(null);
@@ -17,7 +17,9 @@ export default class CommonModel {
17
17
  (typeof value === "string" || typeof value === "object")) {
18
18
  value = new ObjectID(value);
19
19
  }
20
- if (column.type === TableColumnType.Date && typeof value === "string") {
20
+ if ((column.type === TableColumnType.Date ||
21
+ column.type === TableColumnType.DateTime64) &&
22
+ typeof value === "string") {
21
23
  value = OneUptimeDate.fromString(value);
22
24
  }
23
25
  if (column.type === TableColumnType.JSON && typeof value === "string") {