Skip to content

Commit 6b82415

Browse files
authored
Merge pull request #6723 from nextcloud-libraries/fix/localize-format-date-time-picker
fix(NcDateTimePicker): localize the default formatting
2 parents d1d3536 + db13c0f commit 6b82415

2 files changed

Lines changed: 51 additions & 13 deletions

File tree

src/components/NcDateTimePicker/NcDateTimePicker.vue

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ const props = withDefaults(defineProps<{
215215
216216
/**
217217
* Preview format for the picker input field.
218-
* @default 'yyyy-MM-dd HH:mm'
218+
*
219+
* @default Intl.DateTimeFormat is used to format dates and times
219220
* @see https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
220221
*/
221222
format?: string
@@ -335,20 +336,37 @@ const placeholderFallback = computed(() => {
335336
return t('Select date and time')
336337
})
337338
339+
/**
340+
* The date (time) formatting to be used by the library.
341+
* We use the provided format if possible, otherwise we provide a formatting function
342+
* which uses the browsers Intl API to format the date / time in the current users locale.
343+
*/
338344
const realFormat = computed(() => {
339345
if (props.format) {
340346
return props.format
341-
} else if (props.type === 'datetime' || props.type === 'range-datetime') {
342-
return 'yyyy-MM-dd HH:mm'
343-
} else if (props.type === 'date' || props.type === 'range') {
344-
return 'yyyy-MM-dd'
345347
} else if (props.type === 'week') {
348+
// cannot format weeks with Intl.
346349
return 'RR-II'
350+
}
351+
352+
let formatter: Intl.DateTimeFormat | undefined
353+
if (props.type === 'datetime' || props.type === 'range-datetime') {
354+
formatter = new Intl.DateTimeFormat(getCanonicalLocale(), { dateStyle: 'medium', timeStyle: 'short' })
355+
} else if (props.type === 'date' || props.type === 'range') {
356+
formatter = new Intl.DateTimeFormat(getCanonicalLocale(), { dateStyle: 'medium' })
347357
} else if (props.type === 'month') {
348-
return 'yyyy-MM'
358+
formatter = new Intl.DateTimeFormat(getCanonicalLocale(), { year: 'numeric', month: '2-digit' })
349359
} else if (props.type === 'year') {
350-
return 'yyyy'
360+
formatter = new Intl.DateTimeFormat(getCanonicalLocale(), { year: 'numeric' })
351361
}
362+
363+
if (formatter) {
364+
return (input: Date | [Date, Date]) => Array.isArray(input)
365+
? formatter.formatRange(...input)
366+
: formatter.format(input)
367+
}
368+
369+
// fallback to default formatting
352370
return undefined
353371
})
354372

tests/component/components/NcDateTimePicker.spec.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ test('aria-label set on input element', async ({ mount, page }) => {
1818
})
1919

2020
const testcases = [
21-
['datetime', new Date(2000, 0, 2, 3, 4), '2000-01-02 03:04'],
22-
['date', new Date(2000, 0, 2, 3, 4), '2000-01-02'],
21+
['datetime', new Date(2000, 0, 2, 3, 4), 'Jan 2, 2000, 3:04 AM'],
22+
['date', new Date(2000, 0, 2, 3, 4), 'Jan 2, 2000'],
2323
['week', new Date(2000, 0, 2, 3, 4), '1999-52'],
24-
['month', new Date(2000, 0, 2, 3, 4), '2000-01'],
24+
['month', new Date(2000, 0, 2, 3, 4), '01/2000'],
2525
['year', new Date(2000, 0, 2, 3, 4), '2000'],
26-
['range', [new Date(2000, 0, 1), new Date(2000, 0, 7)] as [Date, Date], '2000-01-01 - 2000-01-07'],
27-
['range-datetime', [new Date(2000, 0, 1, 2, 3), new Date(2000, 0, 7, 8, 9)] as [Date, Date], '2000-01-01 02:03 - 2000-01-07 08:09'],
26+
['range', [new Date(2000, 0, 1), new Date(2000, 0, 7)] as [Date, Date], /Jan 1\s\s7, 2000/i],
27+
['range-datetime', [new Date(2000, 0, 1, 2, 3), new Date(2000, 0, 7, 8, 9)] as [Date, Date], /Jan 1, 2000, 2:03\sAM\s\sJan 7, 2000, 8:09\sAM/i],
2828
] as const
2929

3030
for (const [type, modelValue, expectedValue] of testcases) {
@@ -40,6 +40,26 @@ for (const [type, modelValue, expectedValue] of testcases) {
4040
})
4141
}
4242

43+
const l10nTestcases = [
44+
['datetime', new Date(2000, 0, 2, 3, 4), 'en-GB', '2 Jan 2000, 03:04'],
45+
['date', new Date(2000, 0, 2, 3, 4), 'es-ES', '2 ene 2000'],
46+
['month', new Date(2000, 0, 2, 3, 4), 'de-DE', '01.2000'],
47+
] as const
48+
49+
for (const [type, modelValue, locale, expectedValue] of l10nTestcases) {
50+
test(`Handle localized formatting for date with type: ${type} formatted in locale ${locale}`, async ({ mount, page }) => {
51+
page.addScriptTag({ content: `document.getElementsByTagName('html')[0].dataset.locale = "${locale}";` })
52+
await mount(NcDateTimePicker, {
53+
props: {
54+
modelValue,
55+
type,
56+
},
57+
})
58+
59+
await expect(page.getByRole('textbox')).toHaveValue(expectedValue)
60+
})
61+
}
62+
4363
test('Today is selected by default', async ({ mount, page }) => {
4464
await page.clock.setSystemTime(new Date(2000, 0, 22))
4565

@@ -49,7 +69,7 @@ test('Today is selected by default', async ({ mount, page }) => {
4969
},
5070
})
5171

52-
await expect(page.getByRole('textbox')).toHaveValue('2000-01-22')
72+
await expect(page.getByRole('textbox')).toHaveValue('Jan 22, 2000')
5373

5474
// see also menu is checked
5575
await page.getByRole('textbox').click()

0 commit comments

Comments
 (0)