本文解析 ImportantDays 项目中 dayjs 库的使用方式包括 dayjs 的引入、在 DateUtil/DateModel/CalendarVM 中的应用场景、与原生 Date 对象的互转以及 dayjs 在鸿蒙 ArkTS 环境中的实践要点。一、dayjs 简介dayjs 是一个轻量级的 JavaScript 日期库API 设计与 moment.js 兼容但体积仅 2KB。核心特性特性说明轻量2KBgzip 后不可变所有操作返回新对象链式调用dayjs().add(1, day).format(YYYY-MM-DD)插件系统可按需引入功能二、项目中的引入oh-package.json5 依赖{dependencies:{dayjs:^1.11.x}}导入方式// DateUtil.etsimportdayjsfromdayjs;// DateModel.etsimportdayjsfromdayjs;// CalendarVM.etsimportdayjsfromdayjs;// MonthWeekCalendar.etsimportdayjsfromdayjs;// CalendarPage.etsimportdayjsfromdayjs;// BaseCalendar.etsimportdayjsfromdayjs;项目中有 6 个文件导入了 dayjs覆盖了所有需要日期处理的模块。三、dayjs 在 DateUtil 中的应用格式化staticgetFormatDate(date:Date|dayjs.Dayjs):string{returndayjs(date).format(YYYY-MM-DD);}staticgetFullDateStr(date:Date):string{returndayjs(date).format(YYYY年MM月DD日);}staticgetDateTimeStr(date:Date):string{returndayjs(date).format(YYYY-MM-DD HH:mm);}常用格式化占位符占位符含义示例YYYY四位年份2026MM两位月份07DD两位日期17HH24小时制23mm分钟07ss秒00日期判断staticisToday(date:Date|dayjs.Dayjs):boolean{returndayjs(date).isSame(dayjs(),day);}isSame的第二个参数指定比较粒度day比较到天month比较到月year比较到年获取月份天数staticgetDaysByMonth(year:number,month:number):number{returndayjs().year(year).month(month).daysInMonth();}daysInMonth()自动处理闰年dayjs().year(2024).month(1).daysInMonth()→ 29闰年二月dayjs().year(2025).month(1).daysInMonth()→ 28平年二月星期名称staticgetWeekdayName(date:Date|dayjs.Dayjs):string{constnames[周日,周一,周二,周三,周四,周五,周六];returnnames[dayjs(date).day()];}dayjs().day()返回 0-60周日。日期键生成staticbuildKeyByDate(date:Date|dayjs.Dayjs):string{returndayjs(date).format(YYYY-MM-DD);}日期范围staticgetDateRangeKeys(startDate:Date,endDate:Date):string[]{constkeys:string[][];conststartdayjs(startDate);constenddayjs(endDate);letcurrentstart;while(current.isBefore(end)||current.isSame(end,day)){keys.push(current.format(YYYY-MM-DD));currentcurrent.add(1,day);}returnkeys;}使用isBeforeisSame组合判断范围边界add(1, day)递增日期。四、dayjs 在 DateModel 中的应用exportclassDateModel{dayjsObj:dayjs.Dayjs;day:number;lunarDay:string;isCurrentMonth:boolean;dateStr:string;constructor(dayjsObj:dayjs.Dayjs,isCurrentMonth:booleantrue){this.dayjsObjdayjsObj;this.daydayjsObj.date();// 获取日期数字this.lunarDay;this.isCurrentMonthisCurrentMonth;this.dateStrdayjsObj.format(YYYY-MM-DD);// 预生成日期键}}设计要点存储 dayjs 对象dayjsObj保存原始 dayjs 对象便于后续操作预计算属性day和dateStr在构造时预计算避免渲染时重复调用农历预留lunarDay预留农历字段当前为空五、dayjs 在 CalendarVM 中的应用当前日期TraceselectDate:dayjs.Dayjsdayjs();使用dayjs()获取当前时间作为初始选中日期。月份数据生成getDateList(date:dayjs.Dayjs):DateModelList{constyeardate.year();constmonthdate.month();constfirstDaydayjs().year(year).month(month).date(1);constdaysInMonthdate.daysInMonth();letfirstDayWeekday:numberfirstDay.day();firstDayWeekday(firstDayWeekday-this.startWeekdayWEEK_DAYS)%WEEK_DAYS;// 上月填充for(letifirstDayWeekday-1;i0;i--){constprevDatefirstDay.subtract(i1,day);list.push(newDateModel(prevDate,false));}// 当月for(leti1;idaysInMonth;i){constdayDatedayjs().year(year).month(month).date(i);list.push(newDateModel(dayDate,true));}// 下月填充while(list.length42){constlastDatelist[list.length-1].dayjsObj;constnextDatelastDate.add(1,day);list.push(newDateModel(nextDate,false));}returnlist;}dayjs 链式操作dayjs().year(year).month(month).date(1)创建指定年月的第一天dayjs()获取当前时间.year(year)设置年份.month(month)设置月份.date(1)设置为1号日期加减firstDay.subtract(i1,day)// 向前推 i1 天lastDate.add(1,day)// 向后推 1 天subtract和add的第二个参数支持day、week、month、year、hour、minute、second。初始化数据privateinitCalendarData():void{this.monthWeekDataSource.clearData();for(leti-1;i1;i){constdatedayjs().add(i,month);// 当前月 ± ithis.monthWeekDataSource.addData(this.getDateList(date));}}日期导航goToToday():void{this.selectDatedayjs();this.initCalendarData();}getCurrentMonthTitle():string{returnthis.selectDate.format(YYYY年MM月);}getCurrentYearTitle():string{return${this.selectDate.year()}年;}日期比较isToday(date:dayjs.Dayjs):boolean{returndate.isSame(dayjs(),day);}isDateSelect(date:dayjs.Dayjs):boolean{returndate.isSame(this.selectDate,day);}六、dayjs 在组件中的应用CalendarPage 中的日期操作// 上一月this.vm.selectDatethis.vm.selectDate.subtract(1,month);// 下一月this.vm.selectDatethis.vm.selectDate.add(1,month);// 日期选择器回调constdatedayjs().year(value.year).month(value.month).date(value.day);this.vm.changeDate(date);// 格式化this.selectDate.format(YYYY-MM-DD)MonthWeekCalendar 中的日期比较// 月份比较if(!this.vm.selectDate.isSame(middleDate,month)){this.vm.selectDatemiddleDate;}BaseCalendar 中的日期操作privategetDateList():DateModel[]{constdatedayjs().year(this.year).month(this.month);constfirstDaydate.date(1);constdaysInMonthdate.daysInMonth();// ...}七、dayjs 与 Date 的互转Date → dayjsconstdnewDate();constdjdayjs(d);// Date → dayjsdayjs → Dateconstdjdayjs();constddj.toDate();// dayjs → Date项目中的互转场景// CalendarPage 中 DatePicker 回调.onChange((value:DatePickerResult){constdatedayjs().year(value.year).month(value.month).date(value.day);this.vm.changeDate(date);// 传入 dayjs})// MonthWeekCalendar 中日期点击privateonDateClick(dateModel:DateModel):void{this.vm.changeDate(dateModel.dayjsObj);// 传入 dayjsthis.onChangeDay(dateModel.dayjsObj.toDate());// 传入 Date}八、dayjs 的不可变性不可变操作consttodaydayjs();consttomorrowtoday.add(1,day);console.log(today.format(YYYY-MM-DD));// 2026-07-17不变console.log(tomorrow.format(YYYY-MM-DD));// 2026-07-18新对象add、subtract等操作不修改原对象而是返回新对象。与原生 Date 的对比// 原生 Date可变constdnewDate(2026-07-17);d.setDate(d.getDate()1);console.log(d);// 2026-07-18原对象被修改// dayjs不可变constdjdayjs(2026-07-17);constnextdj.add(1,day);console.log(dj.format(YYYY-MM-DD));// 2026-07-17不变console.log(next.format(YYYY-MM-DD));// 2026-07-18新对象不可变性在状态管理中非常重要——避免了意外修改导致的状态混乱。九、性能考量dayjs 对象创建// 日历渲染中会创建大量 dayjs 对象for(leti1;idaysInMonth;i){constdayDatedayjs().year(year).month(month).date(i);list.push(newDateModel(dayDate,true));}每月创建约 42 个 dayjs 对象年视图创建 12 × 42 504 个。dayjs 对象很轻量这个数量级不会有性能问题。预计算优化constructor(dayjsObj:dayjs.Dayjs,isCurrentMonth:booleantrue){this.dayjsObjdayjsObj;this.daydayjsObj.date();// 预计算this.dateStrdayjsObj.format(YYYY-MM-DD);// 预计算}DateModel预计算了day和dateStr避免渲染时重复调用 dayjs 方法。十、总结dayjs 在 ImportantDays 项目中的使用体现了以下实践统一工具类DateUtil封装所有 dayjs 操作双类型兼容方法接受Date | dayjs.Dayjs预计算优化DateModel预计算常用属性不可变操作利用 dayjs 不可变性保障状态安全链式调用dayjs().year().month().date()简洁高效灵活格式化format()支持各种日期格式dayjs 以极小的代价为项目提供了强大的日期处理能力是鸿蒙应用中日期处理的首选方案。