Skip to content

Commit 9597583

Browse files
feat: Added a custom date format parser for checking if the provided date format is valid or not
1 parent b82a334 commit 9597583

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

apps/web/shared/utils.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,97 @@ export const renderJSONContent = (content: unknown) => {
168168
return typeof content === 'string' ? content : JSON.stringify(content);
169169
}
170170
};
171+
172+
export function validateDateFormatString(format: string) {
173+
if (!format || typeof format !== 'string') {
174+
return { isValid: false, error: 'Format must be a non-empty string' };
175+
}
176+
177+
/*
178+
* Valid tokens and separators
179+
* const validSeparators = ['/', '-', '.', ' ', ':', ','];
180+
*/
181+
182+
// Check for valid structure
183+
const formatRegex = /^(YYYY|YY|MM|DD|M|D|[\/\-.\s:,])+$/;
184+
if (!formatRegex.test(format)) {
185+
return {
186+
isValid: false,
187+
error: 'Format contains invalid characters. Use YYYY, YY, MM, DD, M, D and separators (/, -, ., space, :, ,)',
188+
};
189+
}
190+
191+
// Check if format contains at least one valid token
192+
const hasValidToken = /(YYYY|YY|MM|DD|M|D)/.test(format);
193+
if (!hasValidToken) {
194+
return { isValid: false, error: 'Format must contain at least one valid date token (YYYY, YY, MM, DD, M, D)' };
195+
}
196+
197+
// Extract all tokens by replacing them one by one
198+
let tempFormat = format;
199+
let yearCount = 0;
200+
let monthCount = 0;
201+
let dayCount = 0;
202+
203+
// Count YYYY tokens
204+
while (tempFormat.includes('YYYY')) {
205+
yearCount++;
206+
tempFormat = tempFormat.replace('YYYY', '');
207+
}
208+
209+
// Count YY tokens (only if YYYY wasn't found)
210+
while (tempFormat.includes('YY')) {
211+
yearCount++;
212+
tempFormat = tempFormat.replace('YY', '');
213+
}
214+
215+
// Reset for month/day counting
216+
tempFormat = format.replace(/YYYY/g, '').replace(/YY/g, '');
217+
218+
// Count MM tokens
219+
while (tempFormat.includes('MM')) {
220+
monthCount++;
221+
tempFormat = tempFormat.replace('MM', '');
222+
}
223+
224+
// Count M tokens (single M, not part of MM)
225+
const singleMMatches = tempFormat.match(/(?<!M)M(?!M)/g);
226+
monthCount += singleMMatches?.length ?? 0;
227+
228+
// Reset for day counting
229+
tempFormat = format
230+
.replace(/YYYY/g, '')
231+
.replace(/YY/g, '')
232+
.replace(/MM/g, '')
233+
.replace(/(?<!M)M(?!M)/g, '');
234+
235+
// Count DD tokens
236+
while (tempFormat.includes('DD')) {
237+
dayCount++;
238+
tempFormat = tempFormat.replace('DD', '');
239+
}
240+
241+
// Count D tokens (single D, not part of DD)
242+
const singleDMatches = tempFormat.match(/(?<!D)D(?!D)/g);
243+
dayCount += singleDMatches?.length ?? 0;
244+
245+
// Validate counts
246+
if (yearCount > 1) {
247+
return { isValid: false, error: 'Format cannot have multiple year tokens' };
248+
}
249+
250+
if (monthCount > 1) {
251+
return { isValid: false, error: 'Format cannot have multiple month tokens' };
252+
}
253+
254+
if (dayCount > 1) {
255+
return { isValid: false, error: 'Format cannot have multiple day tokens' };
256+
}
257+
258+
// Check that tokens aren't directly adjacent without separator
259+
if (/YYYYMM|YYYYDD|MMDD|DDMM|MMYY|DDYY|YYMM|YYDD/i.test(format)) {
260+
return { isValid: false, error: 'Date tokens must be separated by valid separators' };
261+
}
262+
263+
return { isValid: true, error: null };
264+
}

0 commit comments

Comments
 (0)