Skip to content

Commit 958ecf5

Browse files
committed
fix(formatDate): prevent sequential replacements from corrupting month/weekday names
Use placeholder tokens to protect text values (month names, weekday names, ordinals, AM/PM) during the replacement chain. Letters like 'h' in "March" were being replaced by hour values, producing incorrect output like "Marc10".
1 parent ff18fbc commit 958ecf5

1 file changed

Lines changed: 20 additions & 8 deletions

File tree

src/utility/formatDate.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,26 @@ export function formatDate(date: Date, format: string): string {
4343
const hours12 = hours % 12 || 12;
4444
const isPM = hours >= 12;
4545

46+
// Use placeholders for text values to prevent later replacements from corrupting them
47+
// (e.g., "March" contains "h" which would be replaced by hour values)
48+
const placeholders: string[] = [];
49+
const addPlaceholder = (value: string): string => {
50+
const index = placeholders.length;
51+
placeholders.push(value);
52+
return `\x00${index}\x00`;
53+
};
54+
4655
// Order matters: longer tokens must be replaced before shorter ones
47-
return format
56+
let result = format
4857
.replace(/YYYY/g, year.toString())
4958
.replace(/YY/g, year.toString().slice(-2))
50-
.replace(/MMMM/g, monthNames[month])
51-
.replace(/MMM/g, monthNamesShort[month])
59+
.replace(/MMMM/g, addPlaceholder(monthNames[month]))
60+
.replace(/MMM/g, addPlaceholder(monthNamesShort[month]))
5261
.replace(/MM/g, pad(month + 1))
5362
.replace(/M/g, (month + 1).toString())
54-
.replace(/dddd/g, weekdayNames[weekday])
55-
.replace(/ddd/g, weekdayNamesShort[weekday])
56-
.replace(/Do/g, ordinal(day))
63+
.replace(/dddd/g, addPlaceholder(weekdayNames[weekday]))
64+
.replace(/ddd/g, addPlaceholder(weekdayNamesShort[weekday]))
65+
.replace(/Do/g, addPlaceholder(ordinal(day)))
5766
.replace(/DD/g, pad(day))
5867
.replace(/D/g, day.toString())
5968
.replace(/HH/g, pad(hours))
@@ -64,6 +73,9 @@ export function formatDate(date: Date, format: string): string {
6473
.replace(/m/g, minutes.toString())
6574
.replace(/ss/g, pad(seconds))
6675
.replace(/s/g, seconds.toString())
67-
.replace(/A/g, isPM ? 'PM' : 'AM')
68-
.replace(/a/g, isPM ? 'pm' : 'am');
76+
.replace(/A/g, addPlaceholder(isPM ? 'PM' : 'AM'))
77+
.replace(/a/g, addPlaceholder(isPM ? 'pm' : 'am'));
78+
79+
// Restore placeholders with actual text values
80+
return result.replace(/\x00(\d+)\x00/g, (_, index) => placeholders[parseInt(index, 10)]);
6981
}

0 commit comments

Comments
 (0)