使用自动导入的 useDateFormatter composable 进行日期格式化、转换和操作,基于 @internationalized/date 库实现国际化日期处理。
<script setup lang="ts">
const formatter = useDateFormatter({ locale: 'zh-CN' })
const today = formatter.getToday()
const formattedDate = formatter.format(today)
// "2025年11月29日"
const isoString = formatter.toISO(today)
// "2025-11-29"
</script>
useDateFormatter 基于 Intl.DateTimeFormat 提供本地化日期格式化。null 或 undefined 时会返回空字符串或 null,避免抛出异常。useDateFormatter(options?: DateFormatterOptions): DateFormatter
创建日期格式化器实例。
'zh-CN'。{ dateStyle: 'medium' }。返回包含以下方法和属性的日期格式化器对象。
formatter.format(date)
// "2025年11月29日"
' - '。formatter.formatRange(startDate, endDate)
// "2025年11月1日 - 2025年11月30日"
formatter.formatRange(startDate, endDate, ' 至 ')
// "2025年11月1日 至 2025年11月30日"
', '。formatter.formatArray([date1, date2, date3])
// "2025年11月1日, 2025年11月15日, 2025年11月29日"
formatter.toISO(date)
// "2025-11-29"
formatter.toTimestamp(date)
// 1732838400000
formatter.toUnixTimestamp(date)
// 1732838400
CalendarDate、CalendarDateTime 或 ZonedDateTime。formatter.parse('2025-11-29')
// CalendarDate
formatter.parse('2025-11-29T10:30:00')
// CalendarDateTime
formatter.parse('2025-11-29T10:30:00[Asia/Shanghai]')
// ZonedDateTime
DateValue 类型。DateRange 类型。const converted = formatter.convertData(complexData, formatter.toISO)
// 单个日期
formatter.convertToISO(date)
// "2025-11-29"
// 日期范围
formatter.convertToISO({ start: date1, end: date2 })
// { start: "2025-11-01", end: "2025-11-30" }
// 日期数组
formatter.convertToISO([date1, date2])
// ["2025-11-01", "2025-11-15"]
// 嵌套对象
formatter.convertToISO({
createdAt: date1,
range: { start: date2, end: date3 }
})
// {
// createdAt: "2025-11-01",
// range: { start: "2025-11-20", end: "2025-11-29" }
// }
以下是一个完整的使用示例:
<script setup lang="ts">
import { useAutoForm, useDateFormatter } from '@movk/nuxt'
const { afz } = useAutoForm()
const formatter = useDateFormatter()
// 创建包含日期字段的表单
const schema = afz.object({
startDate: afz.calendarDate('请选择开始日期'),
endDate: afz.calendarDate('请选择结束日期'),
workDays: afz.array(afz.calendarDate(), {
label: '工作日'
}),
birthday: afz.calendarDate('请选择出生日期')
})
const formData = ref({
startDate: formatter.getStartOfMonth(formatter.getToday()),
endDate: formatter.getEndOfMonth(formatter.getToday()),
workDays: [],
birthday: null
})
// 格式化显示
const displayData = computed(() => {
if (!formData.value) return null
return formatter.convertToFormatted(formData.value)
})
// 提交时转换为 ISO 格式
async function handleSubmit() {
const payload = formatter.convertToISO(formData.value)
// payload 示例:
// {
// startDate: "2025-11-01",
// endDate: "2025-11-30",
// workDays: ["2025-11-05", "2025-11-12", "2025-11-19"],
// birthday: "1990-01-01"
// }
await api.submit(payload)
}
// 日期范围处理
const weekRange = computed(() => {
const today = formatter.getToday()
return {
start: formatter.getStartOfWeek(today),
end: formatter.getEndOfWeek(today)
}
})
const weekRangeText = computed(() => {
return formatter.formatRange(weekRange.value.start, weekRange.value.end)
// "2025年11月24日 - 2025年11月30日"
})
// 判断是否为周末
const isWeekendToday = computed(() => {
return formatter.isWeekend(formatter.getToday())
})
</script>
<template>
<div>
<MAutoForm
v-model="formData"
:schema="schema"
@submit="handleSubmit"
/>
<div v-if="displayData" class="mt-4">
<h3>格式化显示</h3>
<pre>{{ displayData }}</pre>
</div>
<div class="mt-4">
<p>本周范围:{{ weekRangeText }}</p>
<p>今天是否为周末:{{ isWeekendToday }}</p>
</div>
</div>
</template>
// 中文
const formatterZH = useDateFormatter({ locale: 'zh-CN' })
formatterZH.format(date) // "2025年11月29日"
// 英文
const formatterEN = useDateFormatter({ locale: 'en-US' })
formatterEN.format(date) // "Nov 29, 2025"
// 日文
const formatterJA = useDateFormatter({ locale: 'ja-JP' })
formatterJA.format(date) // "2025年11月29日"
// 短日期
useDateFormatter({
formatOptions: { dateStyle: 'short' }
})
// 2025/11/29
// 中等日期
useDateFormatter({
formatOptions: { dateStyle: 'medium' }
})
// 2025年11月29日
// 长日期
useDateFormatter({
formatOptions: { dateStyle: 'long' }
})
// 2025年11月29日
// 完整日期
useDateFormatter({
formatOptions: { dateStyle: 'full' }
})
// 2025年11月29日星期六
// 日期和时间
useDateFormatter({
formatOptions: {
dateStyle: 'medium',
timeStyle: 'short'
}
})
// 2025年11月29日 14:30
// 自定义格式
useDateFormatter({
formatOptions: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
}
})
// 2025年11月29日星期六
默认情况下,useDateFormatter 使用本地时区。如需指定时区,使用 timeZone 参数:
const formatter = useDateFormatter({
timeZone: 'Asia/Shanghai'
})
// 或使用其他时区
const formatterNY = useDateFormatter({
timeZone: 'America/New_York'
})
时区标识符遵循 IANA 时区数据库规范。常用时区包括:
'Asia/Shanghai' - 中国标准时间'America/New_York' - 美国东部时间'Europe/London' - 英国时间'Asia/Tokyo' - 日本标准时间useDateFormatter 提供了类型守卫函数用于运行时类型检查:
const formatter = useDateFormatter()
// 检查是否为 DateValue
if (formatter.isDateValue(someValue)) {
// TypeScript 自动推断 someValue 为 DateValue 类型
const formatted = formatter.format(someValue)
}
// 检查是否为 DateRange
if (formatter.isDateRange(someValue)) {
// TypeScript 自动推断 someValue 为 DateRange 类型
const { start, end } = someValue
}
在 AutoForm 中使用日期字段时,建议使用 convertToISO() 进行批量转换后提交:
<script setup lang="ts">
const { afz } = useAutoForm()
const formatter = useDateFormatter()
const schema = afz.object({
eventDate: afz.calendarDate(),
eventRange: afz.calendarDate({
controlProps: { mode: 'range' }
})
})
const formData = ref()
async function handleSubmit() {
// 自动处理所有日期字段的转换
const payload = formatter.convertToISO(formData.value)
// payload.eventDate: "2025-11-29"
// payload.eventRange: { start: "2025-11-01", end: "2025-11-30" }
await api.submit(payload)
}
</script>