036-dayjs日期库在鸿蒙应用中的集成与最佳实践

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 文件中使用:

importdayjsfrom'dayjs'

2.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 天数差计算

// 计算两个日期之间的天数差conststartDate='2026-01-01'constendDate='2026-07-08'constdaysDiff=dayjs(endDate).diff(dayjs(startDate),'day')// 结果: 188 天// 按月差计算constmonthDiff=dayjs(endDate).diff(dayjs(startDate),'month')// 结果: 6 个月// 精确到小数constexactDiff=dayjs(endDate).diff(dayjs(startDate),'day',true)

isBefore / isAfter 日期比较

consttoday=dayjs()constdeadline=dayjs('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')// true

startOf / endOf 获取时间范围

// 获取月份起止日期(常用于筛选查询)constmonthStart=dayjs().startOf('month').format('YYYY-MM-DD')constmonthEnd=dayjs().endOf('month').format('YYYY-MM-DD')// 获取年度起止constyearStart=dayjs().startOf('year').format('YYYY-MM-DD')constyearEnd=dayjs().endOf('year').format('YYYY-MM-DD')

三、dayjs 插件介绍

dayjs 的核心包只包含最基础的解析和格式化功能,更多高级功能通过插件扩展:

importadvancedFormatfrom'dayjs/plugin/advancedFormat'importtimezonefrom'dayjs/plugin/timezone'importlocalizedFormatfrom'dayjs/plugin/localizedFormat'importutcfrom'dayjs/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.currentMonth=dayjs(this.currentMonth).subtract(1,'month').format('YYYY-MM')this.loadMonthData()}// 切换到下个月nextMonth(){this.currentMonth=dayjs(this.currentMonth).add(1,'month').format('YYYY-MM')this.loadMonthData()}
  • 使用dayjs().subtract(n, 'month')实现月份的向前/向后切换
  • 首页的月份切换带动整个账单数据重新加载
  • 月份格式统一使用YYYY-MM存储和传递

5.2 DailyBillGroup 按 dateStr 分组

在账单列表展示中,需要通过 dayjs 将交易记录按日期分组:

// 按日期分组constgroups=transactions.reduce((acc,tx)=>{constdateStr=dayjs(tx.date).format('YYYY-MM-DD')if(!acc[dateStr])acc[dateStr]=[]acc[dateStr].push(tx)returnacc},{}asRecord<string,Transaction[]>)// 分组标题格式化constgroupTitle=dayjs(dateStr).format('MM月DD日')// 07月08日// 计算该日总金额constdayTotal=groups[dateStr].reduce((sum,tx)=>sum+tx.amount,0)

六、日期处理常见陷阱

陷阱说明解决方案
时区问题dayjs 默认使用本地时区,与 UTC 时间可能不一致使用 utc 插件显式处理时区,服务端交互统一使用 UTC
闰年处理2月29日在非闰年不存在使用 dayjs 的 API 操作日期(如endOf('month')),避免手动计算
月末日期1月31日加一个月是2月28/29日使用endOf('month')获取月末安全值
日期字符串格式2026/07/082026-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 会正确处理,如果结果无效会回滚到月末}// 正确处理月末constlastDayOfMonth=dayjs('2026-02-01').endOf('month').format('YYYY-MM-DD')// 2026年不是闰年,返回 2026-02-28

七、替代方案对比

维度Date 原生dayjsLuxon
包体积内置,0KB2KB(核心)~50KB
API 友好度较低(getMonth 从0开始)高(Moment.js 兼容)高(不可变 API)
国际化基础插件支持内置支持
时区支持手动处理timezone 插件内置
鸿蒙兼容性✅ 原生支持✅ 已验证⚠️ 需测试
推荐度简单场景⭐ 推荐复杂国际化场景

选型建议:在鸿蒙记账应用中,dayjs 是平衡体积和功能的最佳选择。Date 原生对象 API 不够友好(月份从 0 开始、格式化需要手动实现),而 Luxon 体积较大且鸿蒙兼容性未充分验证。dayjs 仅 2KB 的核心包配合按需加载的插件机制,既能满足记账应用的日期处理需求,又不会显著增加应用体积。

八、参考文档

  • oh-package 第三方库管理
  • dayjs 官方文档
  • ArkTS 模块化开发