Skip to content

Commit a648b39

Browse files
author
Gurgen
committed
refactor: created formatDate utility functions, added tests
1 parent 7a90c08 commit a648b39

File tree

7 files changed

+205
-327
lines changed

7 files changed

+205
-327
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { getCurrentInstance, type ComponentInternalInstance } from 'vue'
2+
import { format } from 'date-fns'
3+
import { enGB, es, ru } from 'date-fns/locale'
4+
import { LOCALE } from '@/common/components/date'
5+
6+
type LocaleCode = LOCALE.enGB | LOCALE.es | LOCALE.ru
7+
8+
declare global {
9+
interface Window {
10+
Vue?: {
11+
prototype: {
12+
$i18n?: {
13+
locale?: string | { value: string }
14+
}
15+
}
16+
}
17+
}
18+
}
19+
20+
const localeMap = {
21+
[LOCALE.enGB]: enGB,
22+
[LOCALE.ru]: ru,
23+
[LOCALE.es]: es,
24+
} as const
25+
26+
function detectI18nLocale(): LocaleCode | null {
27+
try {
28+
// Vue 3 detection with type safety
29+
const instance = getCurrentInstance() as ComponentInternalInstance
30+
31+
/* eslint-disable @typescript-eslint/no-explicit-any */
32+
const vue3Locale = (instance?.proxy as any)?.$i18n?.locale
33+
if (vue3Locale) return normalizeLocale(vue3Locale)
34+
35+
// Vue 2 detection with proper window reference
36+
if (typeof window !== 'undefined' && window.Vue?.prototype?.$i18n?.locale) {
37+
return normalizeLocale(window.Vue.prototype.$i18n.locale)
38+
}
39+
} catch (e) {
40+
console.warn('i18n detection failed:', e)
41+
}
42+
return null
43+
}
44+
function normalizeLocale(locale: string | { value: string }): LocaleCode {
45+
const rawLocale = typeof locale === 'object' ? locale.value : locale
46+
47+
if (rawLocale.startsWith('es')) return LOCALE.es
48+
if (rawLocale.startsWith('ru')) return LOCALE.ru
49+
return LOCALE.enGB // Default fallback
50+
}
51+
export const formatDateLat = (date: Date | string) =>
52+
format(date, 'dd/MM/yyyy', {
53+
locale: localeMap[LOCALE.enGB],
54+
})
55+
56+
export const formatDateRu = (date: Date | string) =>
57+
format(date, 'dd.MM.yyyy', {
58+
locale: localeMap[LOCALE.ru],
59+
})
60+
export const formatTime = (date: Date | string, localeCode?: LocaleCode) => {
61+
const effectiveLocale = localeCode || detectI18nLocale() || LOCALE.enGB
62+
return format(date, 'HH:mm', {
63+
locale: localeMap[effectiveLocale],
64+
})
65+
}
66+
67+
export const formatDate = (date: Date | string, locale?: LocaleCode) => {
68+
const effectiveLocale = locale || detectI18nLocale() || LOCALE.enGB
69+
return effectiveLocale === LOCALE.ru
70+
? formatDateRu(date)
71+
: formatDateLat(date)
72+
}
73+
74+
export const formatDateTime = (date: Date | string, locale?: LocaleCode) => {
75+
const effectiveLocale = locale || detectI18nLocale() || LOCALE.enGB
76+
return format(date, 'Pp', {
77+
locale: localeMap[effectiveLocale],
78+
})
79+
}
Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,32 @@
11
<template>
2-
<span>{{ formattedDate }}</span>
2+
<span :class="$attrs.class">
3+
{{ formattedDate }}
4+
</span>
35
</template>
46

57
<script lang="ts" setup>
6-
import { LOCALE, MONTH_FORMAT, WEEK_FORMAT } from '@/common/components/date'
8+
import { LOCALE } from '@/common/components/date'
9+
import { formatDate, formatDateTime } from '@/host/__util__/formatDate'
710
import { computed, PropType } from 'vue'
8-
import { format } from 'date-fns'
9-
import { enGB, es, ru } from 'date-fns/locale'
1011
1112
const props = defineProps({
13+
date: {
14+
type: [Date, String] as PropType<Date | string>,
15+
required: true,
16+
},
1217
locale: {
1318
type: String as unknown as PropType<LOCALE>,
1419
default: LOCALE.enGB,
1520
},
16-
weekFormat: {
17-
type: String as unknown as PropType<WEEK_FORMAT>,
18-
default: WEEK_FORMAT.NONE,
19-
},
20-
ignoreYear: {
21-
type: Boolean,
22-
default: false,
23-
},
2421
withTime: {
2522
type: Boolean,
2623
default: false,
2724
},
28-
monthFormat: {
29-
type: String as unknown as PropType<MONTH_FORMAT>,
30-
default: MONTH_FORMAT.DEFAULT,
31-
},
32-
})
33-
34-
const currentLocale = computed(() => {
35-
const localeMap = {
36-
[LOCALE.enGB]: enGB,
37-
[LOCALE.ru]: ru,
38-
[LOCALE.es]: es,
39-
}
40-
return localeMap[props.locale] || enGB
41-
})
42-
43-
const separator = computed(() => {
44-
if (props.monthFormat === MONTH_FORMAT.DEFAULT) {
45-
return props.locale === LOCALE.ru ? '.' : '/'
46-
}
47-
return ' '
4825
})
4926
5027
const formattedDate = computed(() => {
51-
const date = new Date()
52-
const options = { locale: currentLocale.value }
53-
54-
const day = format(date, 'd', options)
55-
const month = format(date, props.monthFormat, options)
56-
let result = `${day}${separator.value}${month}`
57-
58-
if (!props.ignoreYear) {
59-
const year = format(date, 'yyyy', options)
60-
result += `${separator.value}${year}`
61-
}
62-
63-
if (props.weekFormat !== WEEK_FORMAT.NONE) {
64-
const week = format(date, props.weekFormat, options)
65-
result += `, ${week}`
66-
}
67-
68-
if (props.withTime) {
69-
const time = format(date, 'p', options)
70-
result += `, ${time}`
71-
}
72-
73-
return result
28+
return props.withTime ?
29+
formatDateTime(props.date, props.locale) :
30+
formatDate(props.date, props.locale)
7431
})
7532
</script>
Lines changed: 5 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,9 @@
11
<template>
2-
<span>{{ formattedDay }}</span>
3-
<span>{{ `${defineSeparator+formattedMonth}` }}</span>
4-
<span v-if="!ignoreYear">{{ `${!ignoreYear ? defineSeparator : ' '}${formattedYear}` }}</span>
5-
<span v-if="weekFormat">{{ `, ${formattedWeek}` }}</span>
6-
<span v-if="withTime">{{ `, ${formattedTime}` }}</span>
7-
</template>
2+
<div><UiDate date='2024-03-12' /></div>
83

4+
</template>
5+
96
<script lang="ts" setup>
10-
11-
import { LOCALE, MONTH_FORMAT, WEEK_FORMAT } from '@/common/components/date'
12-
import { computed, PropType } from 'vue'
13-
import { format } from 'date-fns'
14-
import { enGB, es, ru } from 'date-fns/locale'
15-
16-
17-
18-
const props = defineProps({
19-
locale: {
20-
type: String as unknown as PropType<LOCALE>,
21-
default: LOCALE.enGB,
22-
},
23-
weekFormat: {
24-
type: String as unknown as PropType<WEEK_FORMAT>,
25-
default: WEEK_FORMAT.NONE,
26-
},
27-
ignoreYear: {
28-
type: Boolean,
29-
default: false,
30-
},
31-
withTime: {
32-
type: Boolean,
33-
default: false,
34-
},
35-
monthFormat: {
36-
type: String as unknown as PropType<MONTH_FORMAT>,
37-
default: MONTH_FORMAT.DEFAULT,
38-
},
39-
})
40-
41-
42-
43-
// eslint-disable-next-line vue/return-in-computed-property
44-
const currentLocale = computed(() => {
45-
if (props.locale === LOCALE.enGB) {
46-
return enGB
47-
} else if (props.locale === LOCALE.ru) {
48-
return ru
49-
} else if (props.locale === LOCALE.es) {
50-
return es
51-
}
52-
})
53-
54-
const formattedDay = computed(() => format(new Date(), 'd', {
55-
locale: currentLocale.value,
56-
}))
57-
const formattedMonth = computed(() => format(new Date(), props.monthFormat, {
58-
locale: currentLocale.value,
59-
}))
60-
const formattedYear = computed(() => format(new Date(), 'yyyy', {
61-
locale: currentLocale.value,
62-
}))
63-
64-
const formattedWeek = computed(() => format(new Date(), props.weekFormat, {
65-
locale: currentLocale.value,
66-
}))
67-
68-
const formattedTime = computed(() => format(new Date(), 'p', {
69-
locale: currentLocale.value,
70-
}))
71-
const defineSeparator = computed(() => {
72-
if (props.monthFormat === MONTH_FORMAT.DEFAULT) {
73-
if (props.locale == LOCALE.ru) {
74-
return '.'
75-
} else return '/'
76-
} else return ' '
77-
})
78-
7+
import UiDate from '@/host/components/date/UiDate.vue'
8+
799
</script>
80-

packages/v1-components/storybook/stories/UiDate.mdx

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,35 @@ import UiDate from './UiDate.example.vue'
77

88
В этой документации описывается работа функций `formatDate()`, `formatDateTime()` и `formatTime()` с различными локализациями в нашем приложении.
99

10-
## formatDate(value, ignoreYear)
10+
## formatDate(value)
1111

1212
Функция `formatDate()` форматирует даты в соответствии с текущими настройками локализации. Принимает два параметра:
13+
1314
- `value`: Строка с датой или объект Date
14-
- `ignoreYear`: Boolean (необязательный) - если true, год будет исключен из вывода
1515

1616
### Примеры использования
1717

1818
```javascript
1919
// Предположим, что дата "2024-01-22"
20-
const date = new Date('2024-01-22');
20+
const date = new Date('2024-01-22')
2121

2222
// Для локали ru_RU
23-
formatDate(date) // "22.01.24"
24-
formatDate(date, true) // "22.01"
23+
formatDate(date) // "22.01.24"
2524

2625
// Для локали en_GB
27-
formatDate(date) // "22/01/24"
28-
formatDate(date, true) // "22/01"
26+
formatDate(date) // "22/01/24"
2927

3028
// Для локали es_ES
31-
formatDate(date) // "22/01/24"
32-
formatDate(date, true) // "22/01"
29+
formatDate(date) // "22/01/24"
3330
```
3431

3532
### Шаблоны форматирования по локалям
3633

37-
| Локаль | Стандартный формат | Формат без года |
38-
|--------|-------------------|-----------------|
39-
| ru_RU | dd.mm.yy | dd.mm |
40-
| en_GB | dd/mm/yy | dd/mm |
41-
| es_ES | dd/mm/yy | dd/mm |
34+
| Локаль | Стандартный формат |
35+
| ------ | ------------------ |
36+
| ru_RU | dd.mm.yy |
37+
| en_GB | dd/mm/yy |
38+
| es_ES | dd/mm/yy |
4239

4340
## formatDateTime(value)
4441

@@ -48,44 +45,38 @@ formatDate(date, true) // "22/01"
4845

4946
```javascript
5047
// Предположим, что дата и время "2024-01-22 15:30:00"
51-
const datetime = new Date('2024-01-22 15:30:00');
48+
const datetime = new Date('2024-01-22 15:30:00')
5249

5350
// Для локали ru_RU
54-
formatDateTime(datetime) // Вернёт "22.01.24 15:30"
51+
formatDateTime(datetime) // Вернёт "22.01.24 15:30"
5552

5653
// Для локали en_GB
57-
formatDateTime(datetime) // Вернёт "22/01/24 15:30"
54+
formatDateTime(datetime) // Вернёт "22/01/24 15:30"
5855

5956
// Для локали es_ES
60-
formatDateTime(datetime) // Вернёт "22/01/24 15:30"
57+
formatDateTime(datetime) // Вернёт "22/01/24 15:30"
6158
```
6259

6360
## formatTime(value)
6461

6562
Функция `formatTime()` форматирует время в 24-часовом формате (HH:mm). Работает с разными типами входных данных.
6663

6764
### Параметры
65+
6866
- `value`: может быть строкой, объектом Date, null или undefined
6967

7068
### Примеры использования
7169

7270
```javascript
7371
// С объектом Date
74-
const date = new Date('2024-01-22 15:30:00');
75-
formatTime(date) // Вернёт "15:30"
72+
const date = new Date('2024-01-22 15:30:00')
73+
formatTime(date) // Вернёт "15:30"
7674

7775
// Со строкой
78-
formatTime('2024-01-22 15:30:00') // Вернёт "15:30"
76+
formatTime('2024-01-22 15:30:00') // Вернёт "15:30"
7977

8078
// С невалидными значениями
81-
formatTime(null) // Вернёт ""
82-
formatTime(undefined) // Вернёт ""
79+
formatTime(null) // Вернёт ""
80+
formatTime(undefined) // Вернёт ""
8381
```
8482

85-
### Примечания
86-
87-
- Время всегда отображается в 24-часовом формате независимо от локали
88-
- Разделитель даты для ru_Ru - ".", для других локалей - "/"
89-
- Год всегда отображается в 2-значном формате (yy)
90-
- Когда `ignoreYear` установлен в true, все локали используют точку (.) в качестве разделителя
91-
- Функции форматирования времени всегда добавляют ведущие нули для часов и минут

0 commit comments

Comments
 (0)