Skip to content

Commit 75e1745

Browse files
committed
feat: enhance dateFormat filter with locale support and extended formatting
- Add timezone offset calculation with getTimezoneOffsetString() - Support locale-specific month and weekday names with English defaults - Add comprehensive format tokens (YYYY/yyyy, MMMM/MMM, dddd/ddd, etc.) - Include AM/PM formatting (A/a) and timezone display (Z) - Maintain backward compatibility with existing dateFormat usage - Support both UTC and local time formatting
1 parent 213c576 commit 75e1745

File tree

1 file changed

+75
-18
lines changed

1 file changed

+75
-18
lines changed

core/STE/evaluator/utils/builtInFilters.js

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ const next = (value) => {
7676
return generator.next()
7777
}
7878

79+
function getTimezoneOffsetString(date) {
80+
const offset = -date.getTimezoneOffset()
81+
const sign = offset >= 0 ? "+" : "-"
82+
const absOffset = Math.abs(offset)
83+
const hours = String(Math.floor(absOffset / 60)).padStart(2, "0")
84+
const minutes = String(absOffset % 60).padStart(2, "0")
85+
return `${sign}${hours}:${minutes}`
86+
}
87+
7988
export const builtInFilters = {
8089
cycle,
8190
next,
@@ -103,54 +112,102 @@ export const builtInFilters = {
103112
return `${number.toFixed(2)} ${symbol}`
104113
},
105114

106-
dateFormat: (value, format = "YYYY-MM-DD", useUTC = true) => {
107-
// Safely handle null or undefined values
108-
if (value === null || value === undefined) {
109-
return ""
110-
}
115+
dateFormat: (value, format = "YYYY-MM-DD", useUTC = true, locale = {}) => {
116+
if (value === null || value === undefined) return ""
111117

112-
// Create a date object from the input value
113118
const date = new Date(value)
119+
if (isNaN(date.getTime())) return `Invalid date: ${value}`
114120

115-
// Check if the date is valid
116-
if (isNaN(date.getTime())) {
117-
return `Invalid date: ${value}`
118-
}
119-
120-
// Define getter functions based on useUTC parameter
121+
// Getters
121122
const getYear = useUTC ? () => date.getUTCFullYear() : () => date.getFullYear()
122123
const getMonth = useUTC ? () => date.getUTCMonth() : () => date.getMonth()
123124
const getDay = useUTC ? () => date.getUTCDate() : () => date.getDate()
124125
const getHours = useUTC ? () => date.getUTCHours() : () => date.getHours()
125126
const getMinutes = useUTC ? () => date.getUTCMinutes() : () => date.getMinutes()
126127
const getSeconds = useUTC ? () => date.getUTCSeconds() : () => date.getSeconds()
128+
const getDayOfWeek = useUTC ? () => date.getUTCDay() : () => date.getDay()
127129

128-
// Get all values at once
129130
const year = getYear()
130-
const month = getMonth() + 1 // Months are 0-based in JavaScript
131+
const month = getMonth() + 1
131132
const day = getDay()
132133
const hours = getHours()
133134
const minutes = getMinutes()
134135
const seconds = getSeconds()
135-
136-
// Create a dictionary of replacements
136+
const dayOfWeek = getDayOfWeek()
137+
const ampm = hours >= 12 ? "PM" : "AM"
138+
const timezoneOffset = useUTC ? "+00:00" : getTimezoneOffsetString(date)
139+
140+
// Fallback to default English if no locale is provided
141+
const defaultLocale = {
142+
monthNames: [
143+
"January",
144+
"February",
145+
"March",
146+
"April",
147+
"May",
148+
"June",
149+
"July",
150+
"August",
151+
"September",
152+
"October",
153+
"November",
154+
"December",
155+
],
156+
monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
157+
weekdayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
158+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
159+
}
160+
161+
const loc = {
162+
...defaultLocale,
163+
...locale,
164+
}
165+
166+
// Replacements map
137167
const replacements = {
138168
YYYY: String(year),
169+
yyyy: String(year),
139170
YY: String(year).slice(-2),
171+
yy: String(year).slice(-2),
172+
173+
MMMM: loc.monthNames[getMonth()],
174+
MMM: loc.monthNamesShort[getMonth()],
175+
mmmm: loc.monthNames[getMonth()],
176+
mmm: loc.monthNamesShort[getMonth()],
177+
140178
MM: String(month).padStart(2, "0"),
141179
M: String(month),
180+
142181
DD: String(day).padStart(2, "0"),
143182
D: String(day),
183+
dd: String(day).padStart(2, "0"),
184+
d: String(day),
185+
186+
dddd: loc.weekdayNames[dayOfWeek],
187+
ddd: loc.weekdayNamesShort[dayOfWeek],
188+
144189
HH: String(hours).padStart(2, "0"),
145190
H: String(hours),
191+
hh: String(hours).padStart(2, "0"),
192+
h: String(hours),
193+
146194
mm: String(minutes).padStart(2, "0"),
147195
m: String(minutes),
196+
148197
ss: String(seconds).padStart(2, "0"),
149198
s: String(seconds),
199+
200+
A: ampm,
201+
a: ampm.toLowerCase(),
202+
203+
Z: timezoneOffset,
150204
}
151205

152-
// Replace tokens in the format string
153-
return format.replace(/YYYY|YY|MM|M|DD|D|HH|H|mm|m|ss|s/g, (match) => replacements[match])
206+
// Use regex to match all supported tokens
207+
return format.replace(
208+
/YYYY|yyyy|YY|yy|MMMM|mmmm|mmm|MM|M|DD|D|dd|d|dddd|ddd|HH|H|hh|h|mm|m|ss|s|A|a|Z/g,
209+
(match) => replacements[match] ?? match
210+
)
154211
},
155212

156213
defaults: (value, ...fallbacks) => {

0 commit comments

Comments
 (0)