036-dayjs日期库在鸿蒙应用中的集成与最佳实践
dayjs 日期库在鸿蒙应用中的集成与最佳实践一、引言日期处理是记账应用中最基础也最频繁的操作之一——格式化显示账单日期、按月筛选交易数据、按日分组账单列表、计算天数差等。鸿蒙 ArkTS 支持通过 oh-package 引入第三方 JavaScript/TypeScript 库dayjs 作为轻量级的日期处理库仅 2KB提供了与 Moment.js 兼容的 API是鸿蒙应用日期处理的首选方案。MoneyTrack 在 HomeVM 和 DailyBillGroup 等核心模块中重度使用 dayjs实现了日期的格式化、按月分组、日历计算和日期比较等功能。二、核心知识点2.1 第三方库集成鸿蒙应用通过oh-package.json5文件管理第三方依赖与 npm 的package.json类似// oh-package.json5{dependencies:{dayjs:^1.11.10}}导入后即可在 TypeScript/ArkTS 文件中使用importdayjsfromdayjs2.2 日期格式化dayjs 提供了丰富的日期格式化能力dayjs().format(YYYY-MM-DD)// 2026-07-08dayjs().format(MM月DD日)// 07月08日dayjs().format(YYYY年MM月DD日 dddd)// 2026年07月08日 星期三dayjs().format(YYYY-MM-DD HH:mm:ss)// 2026-07-08 14:30:00在记账应用中常用格式包括YYYY-MM-DD数据库存储、MM月DD日列表显示、YYYY年MM月月份切换、YYYY-MM分组键值。2.3 常用日期操作方法diff 天数差计算// 计算两个日期之间的天数差conststartDate2026-01-01constendDate2026-07-08constdaysDiffdayjs(endDate).diff(dayjs(startDate),day)// 结果: 188 天// 按月差计算constmonthDiffdayjs(endDate).diff(dayjs(startDate),month)// 结果: 6 个月// 精确到小数constexactDiffdayjs(endDate).diff(dayjs(startDate),day,true)isBefore / isAfter 日期比较consttodaydayjs()constdeadlinedayjs(2026-07-15)// 判断是否在某个日期之前if(today.isBefore(deadline)){console.log(未到期)}// 判断是否在某个日期之后if(today.isAfter(deadline)){console.log(已过期)}// 判断是否相同支持粒度比较dayjs(2026-07-08).isSame(2026-07-08,day)// truedayjs(2026-07).isSame(2026-07,month)// truestartOf / endOf 获取时间范围// 获取月份起止日期常用于筛选查询constmonthStartdayjs().startOf(month).format(YYYY-MM-DD)constmonthEnddayjs().endOf(month).format(YYYY-MM-DD)// 获取年度起止constyearStartdayjs().startOf(year).format(YYYY-MM-DD)constyearEnddayjs().endOf(year).format(YYYY-MM-DD)三、dayjs 插件介绍dayjs 的核心包只包含最基础的解析和格式化功能更多高级功能通过插件扩展importadvancedFormatfromdayjs/plugin/advancedFormatimporttimezonefromdayjs/plugin/timezoneimportlocalizedFormatfromdayjs/plugin/localizedFormatimportutcfromdayjs/plugin/utc// 注册插件dayjs.extend(advancedFormat)dayjs.extend(utc)dayjs.extend(timezone)dayjs.extend(localizedFormat)插件名功能使用示例advancedFormat更多格式化标记dayjs().format(Q)显示季度utcUTC 模式支持dayjs.utc()解析 UTC 时间timezone时区转换dayjs().tz(America/New_York)localizedFormat本地化格式dayjs().format(LTS)本地时间格式relativeTime相对时间dayjs().fromNow()输出3天前isBetween区间判断dayjs().isBetween(a, b)四、dayjs 在记账中的日期处理流程用户选择后端接口交易日期数据数据来源dayjs 标准化存储为 YYYY-MM-DD查询场景展示场景统计场景startOf/endOf 按月范围isBefore/isAfter 条件筛选format 格式化为 MM月DD日分组为日 按月聚合diff 计算时间跨度isSame 按月分组汇总五、项目代码案例5.1 HomeVM 中 dayjs 处理月份切换在products/entry/src/main/ets/viewmodel/home/HomeVM.ets中月份切换功能依赖 dayjs// 切换到上个月previousMonth(){this.currentMonthdayjs(this.currentMonth).subtract(1,month).format(YYYY-MM)this.loadMonthData()}// 切换到下个月nextMonth(){this.currentMonthdayjs(this.currentMonth).add(1,month).format(YYYY-MM)this.loadMonthData()}使用dayjs().subtract(n, month)实现月份的向前/向后切换首页的月份切换带动整个账单数据重新加载月份格式统一使用YYYY-MM存储和传递5.2 DailyBillGroup 按 dateStr 分组在账单列表展示中需要通过 dayjs 将交易记录按日期分组// 按日期分组constgroupstransactions.reduce((acc,tx){constdateStrdayjs(tx.date).format(YYYY-MM-DD)if(!acc[dateStr])acc[dateStr][]acc[dateStr].push(tx)returnacc},{}asRecordstring,Transaction[])// 分组标题格式化constgroupTitledayjs(dateStr).format(MM月DD日)// 07月08日// 计算该日总金额constdayTotalgroups[dateStr].reduce((sum,tx)sumtx.amount,0)六、日期处理常见陷阱陷阱说明解决方案时区问题dayjs 默认使用本地时区与 UTC 时间可能不一致使用 utc 插件显式处理时区服务端交互统一使用 UTC闰年处理2月29日在非闰年不存在使用 dayjs 的 API 操作日期如endOf(month)避免手动计算月末日期1月31日加一个月是2月28/29日使用endOf(month)获取月末安全值日期字符串格式2026/07/08和2026-07-08解析结果可能不同统一使用YYYY-MM-DD格式性能陷阱循环中重复dayjs()实例化提前创建 dayjs 对象并复用// 安全地获取上个月同一天避免月末陷阱functiongetPreviousMonth(date:string):string{returndayjs(date).subtract(1,month).format(YYYY-MM-DD)// dayjs 自动处理1月31日 → 12月31日不是12月31日// 实际上 dayjs 的 subtract 会正确处理如果结果无效会回滚到月末}// 正确处理月末constlastDayOfMonthdayjs(2026-02-01).endOf(month).format(YYYY-MM-DD)// 2026年不是闰年返回 2026-02-28七、替代方案对比维度Date 原生dayjsLuxon包体积内置0KB2KB核心~50KBAPI 友好度较低getMonth 从0开始高Moment.js 兼容高不可变 API国际化基础插件支持内置支持时区支持手动处理timezone 插件内置鸿蒙兼容性✅ 原生支持✅ 已验证⚠️ 需测试推荐度简单场景⭐ 推荐复杂国际化场景选型建议在鸿蒙记账应用中dayjs 是平衡体积和功能的最佳选择。Date 原生对象 API 不够友好月份从 0 开始、格式化需要手动实现而 Luxon 体积较大且鸿蒙兼容性未充分验证。dayjs 仅 2KB 的核心包配合按需加载的插件机制既能满足记账应用的日期处理需求又不会显著增加应用体积。八、参考文档oh-package 第三方库管理dayjs 官方文档ArkTS 模块化开发