尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

HarmonyOs应用《重要日》开发第7篇 - 日期处理:dayjs 集成与 DateUtil 封装

HarmonyOs应用《重要日》开发第7篇 - 日期处理:dayjs 集成与 DateUtil 封装
📅 发布时间:2026/7/16 0:15:53

本篇深入讲解 ImportantDays 项目中日期处理的核心工具类 DateUtil,它基于 dayjs 库封装了所有日期计算逻辑,包括倒数计算、重复事件处理、日期格式化等。

一、为什么选择 dayjs?

1.1 dayjs 简介

dayjs 是一个轻量级的 JavaScript 日期处理库,API 设计与 moment.js 兼容,但体积只有 2KB。在 HarmonyOS 的 ArkTS 环境中,dayjs 通过 OpenHarmony 包管理器安装使用。

1.2 对比原生 Date API

// 原生 Date:计算两个日期相差天数constdiff=Math.floor((newDate('2026-03-15').getTime()-newDate('2026-01-01').getTime())/86400000);// dayjs:同样的计算constdiff=dayjs('2026-03-15').diff(dayjs('2026-01-01'),'day');

dayjs 的优势:

  • API 简洁:链式调用,代码可读性高
  • 功能丰富:日期加减、比较、格式化一站式解决
  • 不可变性:操作返回新对象,不修改原对象
  • 轻量:压缩后仅 2KB

二、DateUtil 工具类

2.1 完整实现

// utils/DateUtil.etsimportdayjsfrom'dayjs';import{YearMonth}from'../types/Types';exportclassDateUtil{// 获取今天的日期字符串statictoday():string{returndayjs().format('YYYY-MM-DD');}// 格式化日期staticformatDate(date:string,format:string='YYYY-MM-DD'):string{returndayjs(date).format(format);}// 计算两个日期之间的天数差staticdaysBetween(fromDate:string,toDate:string):number{constfrom=dayjs(fromDate);constto=dayjs(toDate);returnto.diff(from,'day');}// 计算从今天到目标日期的天数(正=未来,负=过去)staticdaysFromToday(targetDate:string):number{returnDateUtil.daysBetween(DateUtil.today(),targetDate);}// 判断是否是今天staticisToday(date:string):boolean{returndayjs(date).isSame(dayjs(),'day');}// 判断是否在本月staticisThisMonth(date:string):boolean{returndayjs(date).isSame(dayjs(),'month');}// 根据偏移量获取年月staticgetYearMonth(offset:number):YearMonth{constd=dayjs().add(offset,'month');return{year:d.year(),month:d.month()+1};}// 从日期字符串获取年月staticgetYearMonthFromDate(date:string):YearMonth{constd=dayjs(date);return{year:d.year(),month:d.month()+1};}// 获取某月的天数staticgetDaysInMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).daysInMonth();}// 获取某月第一天是星期几(0=周日,6=周六)staticgetFirstDayOfMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).date(1).day();}// 格式化年月显示staticformatYearMonth(year:number,month:number):string{return`${year}年${month}月`;}// 格式化中文日期staticformatDateChinese(date:string):string{constd=dayjs(date);return`${d.year()}年${d.month()+1}月${d.date()}日`;}// 获取下一次重复日期staticgetNextOccurrence(date:string,repeatType:number):string{consttarget=dayjs(date);constnow=dayjs();if(repeatType===1){// 每年letnext=target.year(now.year());if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.year(now.year()+1);}returnnext.format('YYYY-MM-DD');}elseif(repeatType===2){// 每月letnext=target.year(now.year()).month(now.month());if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.add(1,'month');}returnnext.format('YYYY-MM-DD');}returndate;}// 获取星期标签staticgetWeekLabel(date:string):string{constday=dayjs(date).day();constlabels=['周日','周一','周二','周三','周四','周五','周六'];returnlabels[day];}// 日期加减天数staticaddDays(date:string,days:number):string{returndayjs(date).add(days,'day').format('YYYY-MM-DD');}// 生成唯一IDstaticgenerateId():string{return`${Date.now()}_${Math.floor(Math.random()*10000)}`;}}

三、核心方法详解

3.1 日期差计算

staticdaysFromToday(targetDate:string):number{returnDateUtil.daysBetween(DateUtil.today(),targetDate);}staticdaysBetween(fromDate:string,toDate:string):number{constfrom=dayjs(fromDate);constto=dayjs(toDate);returnto.diff(from,'day');}

返回值含义:

  • 正数:目标日期在未来(还有 X 天)
  • 负数:目标日期在过去(已过 X 天)
  • 零:就是今天

这个方法是整个应用倒数/正数功能的基础。

3.2 重复事件的下一次日期

staticgetNextOccurrence(date:string,repeatType:number):string{consttarget=dayjs(date);constnow=dayjs();if(repeatType===1){// 每年重复letnext=target.year(now.year());// 替换为今年if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.year(now.year()+1);// 如果今年已过或就是今天,推到明年}returnnext.format('YYYY-MM-DD');}if(repeatType===2){// 每月重复letnext=target.year(now.year()).month(now.month());// 替换为本月if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.add(1,'month');// 如果本月已过或就是今天,推到下月}returnnext.format('YYYY-MM-DD');}returndate;// 不重复,返回原日期}

逻辑流程(以每年重复为例):

原始日期: 2020-03-15,今天: 2026-07-15 1. target = dayjs('2020-03-15') 2. next = target.year(2026) = 2026-03-15 3. 2026-03-15 < 2026-07-15(已过)→ next = next.year(2027) = 2027-03-15 4. 返回 '2027-03-15'

3.3 闰年处理

staticgetDaysInMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).daysInMonth();}

dayjs 内部自动处理闰年。例如:

DateUtil.getDaysInMonth(2024,2);// 29(闰年)DateUtil.getDaysInMonth(2025,2);// 28(平年)

3.4 月初星期计算

staticgetFirstDayOfMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).date(1).day();}

返回值 0-6 对应周日到周六。用于日历视图中确定第一行需要留多少空位。

3.5 中文格式化

staticformatDateChinese(date:string):string{constd=dayjs(date);return`${d.year()}年${d.month()+1}月${d.date()}日`;}staticformatYearMonth(year:number,month:number):string{return`${year}年${month}月`;}

注意 dayjs 的month()返回 0-11,所以需要 +1。

四、在项目中的使用场景

4.1 列表页:计算倒数天数

// MainViewModel.getCountText()consteffectiveDate=this.getEffectiveDate(day);constdays=DateUtil.daysFromToday(effectiveDate);// days > 0: "X天后"// days < 0: "X天前"// days === 0: "今天"

4.2 日历页:生成月份数据

// CalendarDataSource.generateMonth()constdaysInMonth=DateUtil.getDaysInMonth(d.year,d.month);constfirstDayOfWeek=DateUtil.getFirstDayOfMonth(d.year,d.month);// 用这些数据生成 42 格日历(6行 x 7列)

4.3 日历页:标记今天

// CalendarGridView.dayCell()privateisToday(date:string):boolean{returnDateUtil.isToday(date);}

4.4 统计:本月重要日

// MainViewModel.getStats()if(DateUtil.isThisMonth(effectiveDate)){thisMonth++;}

4.5 日历查询:按月日匹配

// MainViewModel.getDaysForDate()if(day.repeatType===RepeatType.YEARLY){constdayMonth=DateUtil.formatDate(day.date,'MM-DD');consttargetMonth=DateUtil.formatDate(date,'MM-DD');returndayMonth===targetMonth;}

五、dayjs 在 ArkTS 中的注意事项

5.1 导入方式

importdayjsfrom'dayjs';

在 oh-package.json5 中声明依赖:

{ "dependencies": { "dayjs": "^1.11.13" } }

5.2 链式调用

dayjs 支持链式调用,但需要注意 ArkTS 的类型推断:

// 正确:分步调用constd=dayjs().year(year).month(month-1);constdays=d.daysInMonth();// 也可以:链式调用constdays=dayjs().year(year).month(month-1).daysInMonth();

5.3 不可变性

dayjs 对象是不可变的,每次操作返回新对象:

consta=dayjs('2026-01-01');constb=a.add(1,'month');// a 仍然是 2026-01-01// b 是 2026-02-01

这在 ArkUI V2 的响应式系统中很重要——不会意外修改被@Trace观察的对象。

六、扩展思考

6.1 时区处理

当前项目没有考虑时区问题。如果需要国际化,可以使用 dayjs 的 UTC 插件:

importutcfrom'dayjs/plugin/utc';dayjs.extend(utc);constutcDate=dayjs.utc('2026-03-15');

6.2 相对时间

如果需要显示"3小时后"这样的相对时间,可以使用 dayjs 的 relativeTime 插件。但本项目只精确到天,不需要。

6.3 自定义解析

dayjs 默认能解析YYYY-MM-DD格式。如果需要解析其他格式:

dayjs('2026年3月15日','YYYY年M月D日');

七、小结

DateUtil 作为项目的日期处理核心,封装了 dayjs 的常用操作,提供了简洁的静态方法接口。从倒数计算到重复事件处理,从日期格式化到日历数据生成,所有日期相关的逻辑都集中在这里,提高了代码的可维护性和可测试性。

相关新闻

  • 流程引擎宕机后流程全丢?Spring Boot 工作流持久化恢复实战,让你的业务永不“断片”
  • Cursor AI布局切换实战手册(从VS Code迁移者必读):12个真实项目踩坑复盘与标准化配置模板
  • 数字IC验证面试核心考点深度剖析与实战应对

最新新闻

  • 广州劳力士回收价格查询和靠谱回收平台实测排行(2026年7月最新数据) - 收的高名表回收平台
  • 免费能玩端游游戏手机软件推荐 手机畅玩端游教学
  • 万国官方售后服务中心电话和完整维修地址实地考察报告+多信源验证(2026年7月更新) - 万国中国官方服务中心
  • 淘天一面:先说下Prefix Caching 的原理然后再说下 Agent 框架怎么不破坏缓存?我说开启prompting caching就自动命中,他摇了摇头...
  • 帝舵中国官方售后服务中心|官方地址及24小时售后电话权威信息通告(2026年7月最新) - 帝舵中国官方服务中心
  • 【华中师范大学、华南师范大学联合主办 | SPIE出版,往届快至会后2.5个月见刊,刊后1.5个月检索 |邀请多位高校专家作主题报告】第五届图像处理、目标检测与跟踪国际学术会议(IPODT 2026)

日新闻

  • Toon Boom Harmony 高效工作流:从节点视图到镜头标记的实战技巧
  • 真力时售后维修电话,为您提供专业腕表保养与故障修复服务权威公示(2026年7月最新) - 亨得利官方服务中心
  • 【C++】类和对象--构造函数进阶(初始化列表与explicit)

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号