@did-btcr2/common 3.0.0 → 4.0.1

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/src/utils/date.ts CHANGED
@@ -9,7 +9,7 @@ export class DateUtils {
9
9
  * @param {Date} [date=new Date()] - The date to format.
10
10
  * @returns {string} The formatted date string.
11
11
  */
12
- static getUTCDateTime(date: Date = new Date()): string {
12
+ static toISOStringNonFractional(date: Date = new Date()): string {
13
13
  const time = date.getTime();
14
14
  if (Number.isNaN(time)) {
15
15
  throw new Error(`Invalid date: ${date}`);
@@ -29,4 +29,102 @@ export class DateUtils {
29
29
  }
30
30
  return Math.floor(date.getTime() / 1000);
31
31
  }
32
+
33
+ /**
34
+ * Validate if a string is a valid UTC date string.
35
+ * @param {string} dateString - The date string to validate.
36
+ * @returns {boolean} True if valid, otherwise false.
37
+ * @throws {Error} If the date string is invalid.
38
+ */
39
+ static dateStringToTimestamp(dateString: string): Date {
40
+ const date = new Date(dateString);
41
+ if (Number.isNaN(date.getTime())) {
42
+ return new Date(0);
43
+ }
44
+ return date;
45
+ }
46
+
47
+ /**
48
+ * Convert a blocktime (Unix timestamp in seconds) to a Date object.
49
+ * @param {number} blocktime - The blocktime in seconds.
50
+ * @returns {Date} The corresponding Date object.
51
+ */
52
+ static blocktimeToTimestamp(blocktime: number): Date {
53
+ return new Date(blocktime * 1000);
54
+ }
55
+
56
+ /**
57
+ * Validates an XMLSCHEMA11-2 dateTime string.
58
+ * Format: [-]YYYY-MM-DDThh:mm:ss[.fractional][Z|(+|-)hh:mm]
59
+ *
60
+ * @see https://www.w3.org/TR/xmlschema11-2/#dateTime
61
+ */
62
+ static isValidXsdDateTime(value?: string): boolean {
63
+ // Empty or undefined value is not a valid dateTime
64
+ if(!value) return false;
65
+
66
+ // Regex for XML Schema dateTime:
67
+ // - Optional leading minus for BCE years
68
+ // - Year: 4+ digits
69
+ // - Month: 01-12
70
+ // - Day: 01-31 (further validated below)
71
+ // - T separator
72
+ // - Hour: 00-23 (24:00:00 is valid end-of-day per spec)
73
+ // - Minute: 00-59
74
+ // - Second: 00-59 (with optional fractional part)
75
+ // - Timezone: Z or (+|-)hh:mm
76
+ const xsdDateTimeRegex =
77
+ /^-?(\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/;
78
+
79
+ const match = value.match(xsdDateTimeRegex);
80
+ if (!match) return false;
81
+
82
+ const [, y, m, d, H, M, S, , tz] = match;
83
+
84
+ const year = parseInt(y, 10);
85
+ const month = parseInt(m, 10);
86
+ const day = parseInt(d, 10);
87
+ const hour = parseInt(H, 10);
88
+ const minute = parseInt(M, 10);
89
+ const second = parseInt(S, 10);
90
+
91
+ // Year 0000 is not valid in XML Schema (no year zero)
92
+ if (year === 0) return false;
93
+
94
+ // Month: 1-12
95
+ if (month < 1 || month > 12) return false;
96
+
97
+ // Day: validate against month (and leap year for February)
98
+ const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
99
+ const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
100
+ const maxDay = month === 2 && isLeapYear ? 29 : daysInMonth[month - 1];
101
+ if (day < 1 || day > maxDay) return false;
102
+
103
+ // Hour: 00-23, or 24:00:00 exactly (end-of-day)
104
+ if (hour === 24) {
105
+ if (minute !== 0 || second !== 0) return false;
106
+ } else if (hour > 23) {
107
+ return false;
108
+ }
109
+
110
+ // Minute: 00-59
111
+ if (minute > 59) return false;
112
+
113
+ // Second: 00-59 (leap second 60 is debatable; XML Schema doesn't explicitly allow it)
114
+ if (second > 59) return false;
115
+
116
+ // Validate timezone offset if present
117
+ if (tz && tz !== 'Z') {
118
+ const tzMatch = tz.match(/^[+-](\d{2}):(\d{2})$/);
119
+ if (tzMatch) {
120
+ const tzHour = parseInt(tzMatch[1], 10);
121
+ const tzMin = parseInt(tzMatch[2], 10);
122
+ if (tzHour > 14 || (tzHour === 14 && tzMin !== 0) || tzMin > 59) {
123
+ return false;
124
+ }
125
+ }
126
+ }
127
+
128
+ return true;
129
+ }
32
130
  }